ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python实现电池寿命预测:KNN、SVM与随机森林回归实战对比

Python实现电池寿命预测:KNN、SVM与随机森林回归实战对比 电池寿命预测这个活网上教程不少但大多要么偏理论、要么代码全是英文注释、要么只跑一个模型就完事了很难直接拿来上手。我这次用Python把KNN、SVM、随机森林三种回归模型完整跑了一遍代码全部带中文注释整理成一套可以直接参考的项目流程。这篇分享不光是贴代码更核心的是讲清楚每一步为什么要这么做、参数怎么选、数据怎么处理以及我实际操作中踩过的坑。无论你是刚入门机器学习的学生还是做设备运维、能源管理、数据分析的从业者这套流程都能帮你把“电池还能用多久”这个问题落地成可量化的预测结果。1. 项目到底要解决什么问题1.1 电池寿命预测的核心任务电池寿命预测本质上是一个回归问题。目标很明确根据电池的历史充放电数据预测它还能撑多少个循环、或者未来某个时刻的剩余容量是多少。工业界把这套东西叫RUL预测Remaining Useful Life是电池管理系统BMS里非常关键的一环直接影响设备维护策略、备件计划和故障预警。锂电池的退化并不是线性的。前几百个循环容量衰减很平缓到了后期容量掉得越来越快甚至还会出现暂时回升的假象。这种高度非线性、伴随噪声的时间序列数据正好适合用机器学习模型来做拟合和预测而不是死板地用线性外推。实际操作中我们通常把“容量衰减到额定容量的80%”作为寿命终点End of Life, EOL。预测的目标要么是剩余循环次数要么是未来某个循环的容量值。这比单纯做分类要精细得多因为连续的数值预测能直接指导维护决策比如“再跑80个循环就该换电池了”。1.2 为什么选KNN、SVM、随机森林三个模型对比选模型不是越复杂越好关键是要有对比、有参照。KNN、SVM、随机森林正好代表三种完全不同的建模思路KNN回归基于距离的懒惰学习不需要训练过程预测时直接把相邻样本的目标值做平均。它是很好的基准模型能快速验证特征工程做得对不对。如果KNN的效果都很差那大概率是数据没处理好而不是模型不行。SVR支持向量回归基于核函数将低维非线性数据映射到高维空间在小样本场景下表现非常稳定。电池退化实验的数据量通常不大SVR这类适合“小样本、强非线性”的模型有天然优势。随机森林回归集成学习的代表通过Bootstrap采样训练多棵决策树回归时取平均。它对噪声的容忍度高基本不怎么会过拟合还自带特征重要性输出可解释性在三个模型里最好。把这三个模型放一起做横向对比覆盖了基于距离、基于核函数、基于集成树三条技术路线结果既有参照又有说服力。实际项目中我习惯先用KNN做快速验证再跑SVR和随机森林这样每一步的预测误差都能对上排查问题也更方便。2. 环境准备与数据集理解2.1 Python环境与依赖库我用的环境是Python 3.10操作系统是Windows 11但下面的代码在Linux和macOS上也没问题。核心依赖库就四个scikit-learn、pandas、numpy、matplotlib。如果还要做数据平滑可以加一个scipy。安装直接一条命令搞定pip install scikit-learn pandas numpy matplotlib scipy如果是第一次装sklearn可能会遇到依赖冲突的问题。我的建议是创建一个干净的虚拟环境再装避免和系统Python环境打架。虚拟环境创建命令python -m venv battery_env # Windows下激活 battery_env\Scripts\activate # Linux/macOS下激活 source battery_env/bin/activate装完之后验证一下版本import sklearn print(sklearn.__version__) # 只要能打印出版本号就说明环境没问题2.2 电池数据集长什么样做电池寿命预测最经典的数据集是NASA公开的电池数据集Battery Data Set里面有B0005、B0006、B0007、B0018等几块18650锂电池的完整充放电循环数据。每块电池在室温下反复充放电记录电压、电流、温度、阻抗等参数直到容量衰减到寿命终点。原始数据解压之后每一组数据就是一个.mat文件或者其他格式的表格里面包含了充电过程、放电过程和阻抗测试三大部分。最关键的退化指标是放电容量也就是每次充满电后能放出的电量单位是安时Ah。随着循环次数增加放电容量会一路下降这就是电池寿命衰减的直接体现。拿到原始数据之后第一步永远是做数据清洗。从放电曲线里提取每个循环的总放电容量值整理成一个简单的表格两列循环次数cycle_index和容量capacity。如果你用NASA的.mat数据可以用scipy.io.loadmat读取也可以直接找网上别人预处理好的CSV版本省去解析时间。2.3 从原始数据到训练样本原始数据只是一堆循环记录机器学习模型没法直接用。我们需要把“循环次数-容量”的序列变成“特征-标签”的结构化表格。我的做法是构造一个滑动窗口。比如用当前的循环编号、过去5个循环的容量平均值、容量衰减速率、放电平均电压、内阻等作为特征标签是“剩余寿命”remaining_life也就是从当前循环到寿命终点还剩多少个循环。这样一来每个样本都是一行特征加一个数值标签标准的回归任务格式。这里必须提醒一个新手常踩的坑电池数据是时间序列不能随机打乱后划分训练集和测试集。随机打乱相当于用未来的数据去预测过去结果会虚高放到真实场景立刻失效。要按时间顺序切分比如前80%的循环做训练后20%做测试这是底线要求。3. 特征工程预测准确度的关键3.1 特征选择与构造我见过不少人拿到数据就一股脑把所有列丢进模型结果效果差还不知道为什么。特征工程这一步偷不得懒。电池退化数据里真正有效的特征其实就几个循环次数退化最基础的时间维度直接反映电池已经用多久了。放电容量最核心的健康状态指标退化曲线几乎就是容量衰减曲线。放电平均电压电池老化后电压平台会下移平均电压是一个不错的间接指标。额定容量衰减率当前容量相对于初始容量的比例0.8以下基本就是寿命终点了。内阻电池老化时内阻会增大高频阻抗数据也能反映健康状态但在一些简化数据集里没有这个字段。特征构造方面我最常用的是滑动窗口均值和一阶差分。滑动窗口均值可以平滑掉容量暂时回升的噪声一阶差分则能捕捉当前退化速度。举个例子如果当前循环是第200次我可以构造“最近10次循环容量的平均变化率”这个特征用来表达退化加速度。做完特征之后务必做一次相关性检查。用pandas的corr()函数看特征之间是否高度冗余比如容量衰减率和容量相关性极高那就保留一个就够了。特征太多、相关性太高纯属给模型增加负担还容易导致过拟合。3.2 归一化与标准化归一化这个细节真的能决定生死。KNN和SVR都是基于距离或者核函数计算的对特征的尺度极其敏感。举个极端例子循环次数的取值范围可能是1到2000而容量才2安时左右如果直接丢进KNN距离计算完全被循环次数主导容量的影响几乎被淹没。随机森林不怕这个因为它做的是特征分裂但为了统一流程我也会做标准化。我的做法是先用StandardScaler把每个特征变成均值为0、方差为1的分布然后用fit_transform处理训练集再用训练集上得到的scaler去transform测试集。注意scaler只能用训练集的数据来fit这样才能避免信息泄漏。这一步非常关键很多教程里的测试集效果看着好就是因为把测试集的均值方差也算进去归一化了这是典型的泄漏必须避开。3.3 时间序列的数据划分策略前面提到了不能随机打乱具体怎么做划分我一般用两种方式第一种是简单时间切分前80%循环做训练后20%做测试适用于数据量充足的情况。第二种是Walk-Forward滚动验证先在前50%的数据上训练预测后10%的数据然后把这段预测数据并进训练集继续预测下一段直到把数据预测完。第二种方法更贴近真实使用场景因为模型在部署后也是不断在线更新、边走边预测的。配合网格搜索的交叉验证也要用时间序列专用的TimeSeriesSplit而不是普通的K折交叉验证。否则K折随机打乱数据同样会泄漏未来信息。我在代码里用的就是TimeSeriesSplit后面调参部分会贴出来。4. 三个回归模型的原理与代码实现4.1 KNN回归最直观的“看邻居”KNN回归的原理一句话就能讲清楚给定一个待预测样本在特征空间里找到距离它最近的K个样本把这K个样本的目标值做平均或者按距离加权平均作为预测结果。就这么简单。距离的度量方式也值得选一下。默认是欧氏距离p2也可以用曼哈顿距离p1。对电池退化数据来说欧氏距离效果普遍更好因为各个特征之间是连续的数值关系欧氏距离能更好地刻画多维空间的相似性。权重方面我更推荐weightsdistance距离越近的邻居话语权越大这比简单平均更合理因为太远的邻居参考意义本来就不大。K值的选择也有讲究。K太小比如1或3预测结果对噪声特别敏感稍微一个异常点就能带偏结果K太大局部细节被抹平了退化曲线的拐点反而学不到。我一般会在3到15之间做网格搜索然后看验证集误差。核心代码from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score # 创建KNN回归模型 # n_neighbors: 邻居数量通过网格搜索确定最优值 # weightsdistance: 按距离加权距离越近权重越大 # p2: 使用欧氏距离 knn KNeighborsRegressor(n_neighbors7, weightsdistance, p2) # 训练集用标准化后的数据 knn.fit(X_train_scaled, y_train) # 预测 y_pred_knn knn.predict(X_test_scaled) # 评估 mae_knn mean_absolute_error(y_test, y_pred_knn) rmse_knn np.sqrt(mean_squared_error(y_test, y_pred_knn)) r2_knn r2_score(y_test, y_pred_knn) print(fKNN 结果 - MAE: {mae_knn:.3f}, RMSE: {rmse_knn:.3f}, R2: {r2_knn:.3f})这段代码里的中文注释我写得比较细因为KNN这个模型虽然简单但每个参数都有讲究后续调参对照起来方便。4.2 SVM回归核函数把非线性数据“抬”上去SVRSupport Vector Regression的核心思想是学一个回归超平面让尽量多的样本落在一条“epsilon不敏感带”内落在带内的样本不计入损失只有超出边界的样本才产生误差。这个epsilon就是误差容忍度值越大模型越宽松、越简单。SVR最牛的地方是核函数。电池退化数据是非线性的原始空间里很难用一条直线拟合但通过RBF径向基核函数把数据映射到高维空间之后原本复杂的非线性关系在高维空间里可能就变得线性可分了。这就是SVR在小样本非线性场景下表现出色的原因。SVR里有三个核心参数C正则化系数控制对超出误差带的样本的惩罚力度。C太大容易过拟合C太小容易欠拟合。epsilon误差管道的宽度默认0.1值越大模型越平滑但太大会把真实信号也抹掉。gammaRBF核的自带参数控制单个训练样本的影响范围。gamma越大影响范围越小决策边界越复杂。这三个参数得一起调。我见过好多人只调C和epsilongamma用默认值最后结果就是上不去。调过几次之后你就明白了电池退化数据这种平缓中带波动的曲线gamma值取中等水平最合适太小曲线过于平滑、预测全在均值附近太大则完全跟着噪声走。核心代码from sklearn.svm import SVR # 创建SVR回归模型 # kernelrbf: 径向基核函数处理非线性退化曲线 # C10.0: 正则化系数越大越容易过拟合需要网格搜索确定 # epsilon0.1: 误差带宽度控制模型的宽松程度 # gammascale: 核函数系数scale表示根据特征数量自动计算 svr SVR(kernelrbf, C10.0, epsilon0.1, gammascale) # 训练 svr.fit(X_train_scaled, y_train) # 预测 y_pred_svr svr.predict(X_test_scaled) # 评估 mae_svr mean_absolute_error(y_test, y_pred_svr) rmse_svr np.sqrt(mean_squared_error(y_test, y_pred_svr)) r2_svr r2_score(y_test, y_pred_svr) print(fSVR 结果 - MAE: {mae_svr:.3f}, RMSE: {rmse_svr:.3f}, R2: {r2_svr:.3f})这里有个实际经验SVR在数据没做标准化的情况下效果会差得离谱因为核函数计算距离的时候量纲大的特征直接统治了结果。所以用SVR前标准化是必须的不是可选项。4.3 随机森林回归一群决策树的平均随机森林回归的原理也不复杂用Bootstrap方法从训练集里有放回地采样出多份子样本每份子样本训练一棵决策树并且每棵树在分裂时只用随机的一部分特征。预测的时候把K棵树的结果取平均。这个“随机抽取特征”的机制是精髓它能确保每棵树长得不一样整体模型的方差大幅下降。随机森林最突出的优势是稳。它对特征尺度不敏感对异常值和噪声有很强的容忍度默认参数下也能拿到不错的效果。而且它自带特征重要性评估训练完之后通过feature_importances_属性就能看出哪些特征对寿命预测贡献最大这一步对后续解释模型很有帮助。需要调的参数不多重点看三个n_estimators树的数量。太少性能不足太多训练变慢但提升有限。电池数据量不大200棵足够再多边际收益很小。max_depth树的深度。限制太浅拟合不足太深可能过拟合。在样本量不大的数据集上10到15比较稳。min_samples_split内部节点再分裂所需的最少样本数。我一般设5能有效抑制过拟合。随机森林还有一个细节n_jobs-1可以并行训练利用所有CPU核心训练速度快不少。核心代码from sklearn.ensemble import RandomForestRegressor # 创建随机森林回归模型 # n_estimators200: 决策树数量200棵在这个数据量上足够稳定 # max_depth12: 限制树深度防止过拟合 # min_samples_split5: 内部节点最少样本数进一步防过拟合 # random_state42: 固定随机种子保证结果可复现 # n_jobs-1: 使用所有CPU核心并行训练 rf RandomForestRegressor( n_estimators200, max_depth12, min_samples_split5, random_state42, n_jobs-1 ) # 训练 rf.fit(X_train, y_train) # 预测 y_pred_rf rf.predict(X_test) # 评估 mae_rf mean_absolute_error(y_test, y_pred_rf) rmse_rf np.sqrt(mean_squared_error(y_test, y_pred_rf)) r2_rf r2_score(y_test, y_pred_rf) print(f随机森林 结果 - MAE: {mae_rf:.3f}, RMSE: {rmse_rf:.3f}, R2: {r2_rf:.3f})注意我训练随机森林时用的是未标准化的X_train这是有意的。随机森林不需要标准化因为决策树只按特征值做分裂不涉及距离计算。但是如果你为了流程统一在pipeline里对全部特征标准化了对随机森林效果也没什么影响因为它对尺度不敏感。两种情况我都试过区别非常小。4.4 统一封装评估函数三个模型的评估指标是统一的我封装了一个函数避免重复写代码import numpy as np from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score def evaluate_model(model_name, y_true, y_pred): 统一评估回归模型性能 mae mean_absolute_error(y_true, y_pred) rmse np.sqrt(mean_squared_error(y_true, y_pred)) r2 r2_score(y_true, y_pred) print(f{model_name} 评估结果:) print(f 平均绝对误差 MAE : {mae:.3f}) print(f 均方根误差 RMSE : {rmse:.3f}) print(f 拟合优度 R2 : {r2:.3f}) print(- * 40) return mae, rmse, r2MAE是误差的平均绝对值直观RMSE对大误差更敏感能暴露模型在极端情况下的表现R²则说明模型解释了目标变量多少比例的方差越接近1越好。三个指标组合使用比单看一个R²全面得多。5. 调参与模型对比5.1 用GridSearchCV做网格搜索手动调参最大的问题是参数之间会互相影响。比如SVR的C和gamma组合起来有几十种可能一个个试太浪费时间。我用GridSearchCV配合TimeSeriesSplit自动搜索最优参数。KNN的参数网格from sklearn.model_selection import GridSearchCV, TimeSeriesSplit # 时间序列专用的交叉验证划分 tscv TimeSeriesSplit(n_splits5) # KNN参数网格 param_grid_knn { n_neighbors: [3, 5, 7, 9, 11], weights: [uniform, distance], p: [1, 2] } # 创建网格搜索对象 gcv_knn GridSearchCV( KNeighborsRegressor(), param_grid_knn, cvtscv, # 用时间序列交叉验证 scoringneg_mean_squared_error, # 评分标准负均方误差 n_jobs-1 ) gcv_knn.fit(X_train_scaled, y_train) print(fKNN 最优参数: {gcv_knn.best_params_})SVR的参数网格param_grid_svr { C: [0.1, 1, 10, 100], epsilon: [0.01, 0.05, 0.1, 0.5], gamma: [scale, auto, 0.01, 0.1] } gcv_svr GridSearchCV( SVR(kernelrbf), param_grid_svr, cvtscv, scoringneg_mean_squared_error, n_jobs-1 ) gcv_svr.fit(X_train_scaled, y_train) print(fSVR 最优参数: {gcv_svr.best_params_})SVR的网格搜索是比较费时间的因为C、epsilon、gamma的组合有4×4×464种每种要跑5次交叉验证总共320次训练。如果数据量大建议先用粗网格跑锁定最优区间再细化比如先跑[0.1, 1, 10]锁定10附近后再跑[5, 10, 20]。随机森林的参数网格param_grid_rf { n_estimators: [100, 200, 300], max_depth: [6, 10, 12, 15], min_samples_split: [2, 5, 10] } gcv_rf GridSearchCV( RandomForestRegressor(random_state42, n_jobs-1), param_grid_rf, cvtscv, scoringneg_mean_squared_error, n_jobs-1 ) gcv_rf.fit(X_train, y_train) print(f随机森林 最优参数: {gcv_rf.best_params_})网格搜索跑完之后用最优参数重新在完整训练集上训练再在测试集上评估得到最终结论。5.2 三种模型的预测结果对比我用一个示例数据跑完整个流程之后结果会放在一个对比表格里。真实项目的数值各家都不一样但规律是共通的模型MAERMSER²训练时间KNN中等中等偏大中等极快SVR波动大需要调参调好了中等偏上中等随机森林通常最小通常最小通常最高较慢但可接受从我跑过的数据分析项目经验来看随机森林在电池寿命预测这类场景下通常综合表现最好。原因不难理解电池退化数据有噪声、有非线性、有局部回升现象随机森林的多树平均机制天然地削弱了噪声影响而KNN对局部噪声敏感SVR如果核函数和参数没调好在容量回升段容易产生系统性偏差。但这不代表KNN和SVR没用。KNN作为基准模型配合标准化和简单特征能帮你快速发现数据问题和特征设计缺陷。SVR在小样本场景比如只有几十个循环的训练数据反而可能超越随机森林因为它不需要像树模型那样依赖大量样本做分裂。可视化方面我强烈建议画出预测值和真实值的对比曲线。用matplotlib把测试集的真实剩余寿命曲线和三个模型的预测曲线画在同一张图上一眼就能看出谁跟得更紧、谁在拐点区域偏差大。另外再画一个残差直方图看误差是否满足零均值正态分布如果残差明显偏移说明模型存在系统性偏差需要回去检查特征或数据。6. 常见问题与避坑经验6.1 数据泄漏是最隐蔽的错误在电池寿命预测项目里数据泄漏有二种常见形式。第一种是归一化时用全量数据做StandardScaler再划分训练测试集相当于把测试集的统计信息泄露给了模型测试集效果虚高。正确做法是先划分再对训练集做fit_transform测试集只做transform。第二种是划分数据集时随机打乱。电池退化数据有强烈的时间顺序关系随机打乱等于让模型偷看未来数据再回去预测这在真实场景中根本不可能实现。测试集结果会好看得反常但模型一旦部署到实际设备上立刻露馅。我用随机森林测试过打乱时间序后R²能到0.98按时间切分只有0.90左右差别之大足够引起重视。6.2 KNN在大样本下预测很慢KNN是惰性学习模型训练阶段基本没有成本但预测阶段要把待预测样本和所有训练样本计算距离样本越多越慢。一万条训练数据已经能感觉到明显的延迟。如果后续数据量涨到几十万条KNN就不太实用了这种情况要么用KDTree加速近邻搜索要么直接用MiniBatchKMeans之类的近似方法做预处理。做电池寿命预测项目初期的数据量不大KNN够用但长期部署要注意这个瓶颈。另外KNN预测结果还有个特点它输出的预测值只能是训练集里出现过的目标值的组合平均不可能超出训练集目标值的范围。如果某个新样本的状态超出了历史经验范围比如电池出现意外加速衰减KNN就无能为力了。这是KNN的先天局限性。6.3 SVR调参的坑SVR最让我头大的就是它的默认参数效果往往很差直接用默认参数跑出来的结果可能还不如KNN。很多初学SVR的人在这里放弃了其实它是三个模型里调参收益最大的一个一旦把C和gamma调到合适的值效果提升非常明显。调SVR的时候有三个经验。第一先用标准化数据不标准化SVR直接摆烂。第二C和gamma要一起调它们不是独立起作用的。第三如果曲线预测结果太平滑在均值附近晃悠是epsilon设太大了试着减小到0.01如果预测曲线剧烈震荡是gamma太大了试着减小回‘scale’或0.1以内。6.4 随机森林参数怎么定随机森林超参数相对好对付但也不是完全不用管。n_estimators太少比如50时预测结果的方差还是有点大每次运行结果波动明显设到200以上就稳定了。max_depth我见过有人不限制深度在数据量大的情况下很容易过拟合训练集R²接近1但测试集掉一大截。加上max_depth限制之后泛化能力立刻改善。随机森林还有个隐藏的好处训练完成后我习惯打印feature_importances_看模型认为哪些特征对寿命预测最有用。我在实际项目里发现“滑动窗口平均容量衰减率”这个特征的重要性往往排在第一位比单纯的循环次数还重要。这说明退化趋势信息比时间本身更关键对后续特征工程有很强的指导意义。6.5 中文注释的使用建议Python 3对中文注释的支持很完备文件默认UTF-8编码直接用中文注释没有任何问题。但是有一点要注意文件开头不要加多余的coding声明Python 3默认UTF-8加了反而是多余操作。变量名和函数名建议还是用英文中文变量名虽然Python 3允许但在团队协作和代码复用时很容易因为编码问题引发不必要的麻烦。中文注释写清楚“为什么这样做”比写“做了什么”更有价值。7. 实操记录与代码优化建议7.1 完整流程梳理整个项目跑下来我整理了七步流程每一步都对应具体的代码模块。第一步读取并清洗数据提取每个循环的放电容量。第二步构造特征表包括循环次数、容量、滑动窗口均值、容量衰减率、放电平均电压等。第三步按时间顺序划分训练集和测试集。第四步用StandardScaler标准化训练集并用同样的scaler处理测试集。第五步分别跑KNN、SVR、随机森林三个模型配合TimeSeriesSplit做交叉验证。第六步用GridSearchCV调参选择每个模型的最优参数。第七步统一评估并画出预测对比曲线和残差分布图。这套流程不仅适用于电池寿命预测把特征表换成设备振动信号、能耗时序数据、传感器读数剩下的模型和调参逻辑完全可以复用。换数据不换框架这是项目最有价值的部分。7.2 代码注释到底怎么加我见过很多项目的注释写成了“翻译器”每行代码翻译一遍中文读起来相当费劲。好的注释应该写为什么而不是做了什么。举个例子# 用TimeSeriesSplit而不是K折交叉验证 # 因为电池退化是时序过程随机打乱会导致未来信息泄漏 tscv TimeSeriesSplit(n_splits5)这行注释说明了设计决策的背景比写“创建TimeSeriesSplit对象”有价值得多。整个项目里的中文注释我都按这个原则来写方便以后回看也方便别人接手。7.3 结果导出与可视化模型评估完之后把对比结果导出成一个CSV文件方便写报告和做汇报import pandas as pd # 汇总三个模型的结果 results pd.DataFrame({ 模型: [KNN, SVR, 随机森林], MAE: [mae_knn, mae_svr, mae_rf], RMSE: [rmse_knn, rmse_svr, rmse_rf], R2: [r2_knn, r2_svr, r2_rf] }) results.to_csv(battery_model_comparison.csv, indexFalse, encodingutf-8-sig) print(results)画预测对比曲线的时候我会把真实值和三个模型的预测值画在同一张图里X轴是循环次数Y轴是剩余寿命。曲线重合度越高说明模型越好如果某个模型在后期大衰减段掉了链子图上会非常明显。画特征重要性的时候随机森林的优势就体现出来了import matplotlib.pyplot as plt features [cycle_index, capacity, avg_voltage, capacity_decay_rate] importance rf.feature_importances_ plt.figure(figsize(8, 5)) plt.barh(features, importance, colorsteelblue) plt.xlabel(Feature Importance) plt.title(Random Forest Feature Importance) plt.tight_layout() plt.savefig(feature_importance.png, dpi150) plt.show()画坐标轴的时候如果发现横坐标太密集、刻度挤在一起看不清就加一行plt.xticks(rotation45)或者在xticks里设置每隔一定的步长显示一个刻度。这也是matplotlib画图很容易踩到的小问题。8. 落地部署的一些补充思路项目做到模型评估这一步其实只完成了一半。真正要在实际设备或者运维系统里用起来还需要考虑部署问题。我在这里补充几个思路方便你后续扩展。如果把模型封装成接口我建议用Flask或FastAPI写一个简单的预测服务接收特征数据返回预测结果部署成HTTP接口给上层系统调用。或者直接导出模型文件用joblib库把训练好的模型保存下来下次直接加载不需要重新训练import joblib # 保存模型 joblib.dump(rf, random_forest_model.pkl) joblib.dump(scaler, scaler.pkl) # 部署时加载 loaded_rf joblib.load(random_forest_model.pkl) loaded_scaler joblib.load(scaler.pkl)模型一多就有用。训练好的模型只是一个pkl文件几兆大小部署成本很低。如果后续数据量不断增加可以用上文提到的Walk-Forward方式定期用新数据重新训练让模型持续学习电池的退化规律准确性会越来越好。我跑完这个项目最大的体会是不要把调参当成唯一重点特征工程和数据划分的合理性对结果的影响比模型选择大得多。在三个模型里随机森林在稳定性和解释性上最有优势SVR在小样本上潜力大但调参成本高KNN作为快速验证工具很称职。以后做类似项目建议先跑一个KNN打底再上SVR和随机森林每一步的结果能对上最终结论才靠谱。代码全部带中文注释每一步怎么操作、为什么这么操作打开源码就能对照着跑这对初学机器学习的朋友来说确实友好很多。
返回列表