ARTICLE DETAIL

资讯详情

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

电池异常检测竞赛方案:时序特征工程与多模型融合实战

电池异常检测竞赛方案:时序特征工程与多模型融合实战 这套“电池异常检测”赛题说难听点就是“卷死人不偿命”。我最后拿到第二名的时候其实没有用什么特别黑科技的模型更多是把数据、特征、验证和融合这四个环节拧成了一条非常稳的流水线。这篇文章不打算讲虚的直接把我在能源AI挑战赛里的完整方案拆开包含我在做的特征怎么设计、模型怎么搭、训练怎么填坑以及最后排名如何去突破的思路。先说清楚这套方案适合谁看如果你正要打类似的异常检测比赛或者实际业务里遇到电池、设备传感器这类时序数据的异常识别问题那这篇文章基本可以当一份SOP来用。不需要你有特别深厚的机器学习理论但如果你能用Python处理数据、调过LightGBM理解起来会非常顺畅。1. 赛题理解与整体思路很多队伍死在起跑线上不是因为模型不给力而是对“电池异常检测”这个任务本身理解得太浅。比赛给的数据通常是一批电芯在长时间充放电循环中的多条时间序列每条序列记录电压、电流、温度、SOC等物理量。目标是要在样本维度上判断哪些电芯或哪些片段存在异常而且往往不是简单的二分类而是需要兼顾检测率和误报率的综合评价指标。1.1 赛制与数据形态先搞清楚数据长什么样这直接决定你后续所有方案的方向。我遇到的比赛数据大概长这样每个电芯有若干次充放电循环每次循环内又有若干秒级的采样点。原始表字段包括时间戳、循环序号、电流、电压、温度、内阻、SOC等但正负样本比例很悬殊异常电芯大概只占到百分之几。这里有个关键点异常标签到底标在哪个粒度。有的比赛标在电芯级别有的标在循环片段级别还有的是纯无监督异常检测只给正常样本。我这次是半监督形态——训练集里有一部分已知异常样本但测试集里混杂更多数据分布偏移的异常所以纯靠有监督硬学是不够的。对数据形态的理解要落到几个具体问题上时间序列的长度是否一致、采样的频率是否均匀、是否存在缺失段、异常是突发型的还是缓慢衰退型的。比赛里大量异常其实是“隐式异常”单看某一个时间点的数值都在正常范围内但放在一段时间窗口里看斜率、波动性、相关性就会露馅。1.2 评价指标与提分空间赛题的得分公式直接决定了你该优化什么。常见的是F1-score也就是precision和recall的调和平均但很多电池异常检测赛题用的是一种“排序期望”类的指标比如对预测概率排序后优先看前K个样本中能抓到多少真实异常类似PK或prAUC。我当时特别做了指标反推如果用的是F1那阈值选择非常关键而阈值又依赖于验证集的划分方式如果用的是排序类指标那目标就是让异常样本的分数尽量靠前而不是纠结于绝对0/1输出。这一点对后续的模型设计有方向性影响。我提交的初期版本是按F1优化的结果榜单上的排名一直卡在中游。后来仔细读了赛题说明发现最终排名用的是另一个排序指标于是我把模型输出从离散的阈值判定改成纯概率排序再在验证集上重新调了阈值名次一下就往上走了几位。1.3 整体方案路线最终我的方案长这样基于领域特征构造的LightGBM和CatBoost作为底座加了一层基于滑动窗口的时序深度模型再叠加无监督重构误差分支最后用两层stacking加上后处理规则做融合。整个流程分四步数据清洗与样本重组把原始循环级时间序列切成长短一致的窗口样本并构造有意义的统计特征。模型分层训练先训一堆拥有不同视角的基模型保证模型之间差异性足够大。特征与模型融合用简单但有效的融合策略不做过于复杂的网络防止过拟合。阈值与后处理根据验证集分布和业务逻辑针对性修正边界样本的判定。每个环节的内容上面碰到的大坑都不少下面每个部分我详细拆开讲。2. 数据清洗与特征工程特征工程不是锦上添花而是决定模型上限的下限。尤其这种物理量时序数据如果你不注入对电池工作原理的理解模型很难凭空学出真正的异常模式。我在比赛中大概花了三分之二的时间在这里。2.1 数据清洗从原始时间序列到样本集合第一步的工作优先级是解决样本割裂的问题。原始数据里一个电芯有多个循环钳段循环次数和采样长度各不相同如果直接当成独立样本模型会混淆“循环阶段不同”和“真的异常”这两种变化。我对样本进行了标准化对齐以电芯ID为分组单元把连续采集的各个循环串联成完整序列。对缺失值做插值但要对异常片段标注后才处理否则会抹掉异常模式。剔除明显非物理的样本点例如突然跳出几百伏的电压值或者温度直接降到绝对零度这种采集器错误。然后是切窗的参数选择。我试过固定步长的滑动窗口和按循环切分两种方式。固定步长滑窗适用于捕捉局部突跳型异常但会让同一个电芯产生大量窗口样本容易导致同一电芯在不同窗口间出现重复计数按循环切分则保留完整充放电过程对缓慢老化型异常更友好。最后我采用了一个混合策略第一版模型用按循环切分的样本第二版模型用滑动窗口样本。两种视角各有盲区最后融合却能互补这也符合为什么融合能提升成绩的逻辑。2.2 特征体系基于领域知识的特征纯用原始电压电流序列丢给树模型效果非常差。真正有价值的特征是把物理量之间的关系、变化过程以及周期性差异给提炼出来。我按这几类特征来建设统计特征每个窗口内电压/电流/温度的均值、方差、峰度、偏度、极差、分位数。这些是基础不加没分加了加分有限所以只能作为底座。变化率特征相邻点电流差的绝对值、电压变化速率、温度变化斜率的陡峭程度。异常电池往往在充放电切换瞬间出现抖动或者电压迟滞。循环间趋势特征同一电芯不同循环之间容量衰减的斜率、内阻上升的速度、恒压阶段时长的变化趋势。这是我最看重的一类特征因为它体现了时间维度上的缓慢漂移。频域特征对电压序列做FFT变换提取主要频率的能量占比和功率谱密度变体。异常振动或者噪声往往在高频段表现出不一样的能量分布。相关性特征电压与电流之间的皮尔逊相关系数SOC与电压之间的映射偏差。电池内部故障会导致本来强相关的物理量出现解耦。举个例子一个某关键电芯的异常类型是电压在恒流充电阶段突然跳变统计特征完全看不出问题因为平均值和方差都在正常范围但滑动窗口的电压一阶差分最大值这一特征能直接把这种现象拉高几个数量级。2.3 降维与筛选特征构造出来会疯狂膨胀我记得我当时堆了大概七八百个特征。盲目往模型里塞带来的问题就是训练慢、过拟合严重、feature importance看起来非常分散。我还是倾向于先用一组简单粗暴的筛选方式删除缺失率高于85%的特征。删除完全相同的常数特征。用LightGBM自带的重要性排序保留累积重要性85%之前的特征。用特征间的相关系数矩阵把相关性超过0.95的重复特征只保留一个。但这里有一个容易踩的坑筛选特征时用了全量数据的关键在比赛里不算泄漏但在真实的项目里这会过拟合。比赛中这属于合理操作不过你仍然需要注意筛选过程本身要放在训练折内部去做否则会在验证集上产生虚高的分数。关于特征工程的整体心得我认为不要只追求“多”而是要让特征覆盖三类异常模式突发型异常、周期相关型异常、趋势漂移型异常。只要这三类视角都有特征能表达模型的基本盘就有保障了。3. 模型架构与集成策略很多队伍到了这一环节就开始各种堆模型LightGBM、XGBoost、CatBoost、LSTM、Transformer全部塞进去再随便加个平均。问题是模型之间如果差异不够大融合结果不会有实质提升。我这次讲究的是“多层视角互补”。3.1 树模型基线LightGBM与CatBoost的取舍树模型是这类表格特征任务的首选基线。我同时训练了LightGBM和CatBoost两个模型的优势不同LightGBM速度极快处理高维稀疏特征和大量类别特征非常顺手在普通统计特征上表现很稳。CatBoost在类别特征处理上有原生优势而且它对噪声容忍度较高预测出来的概率分布跟LightGBM的分布差异比较明显这正好为后续融合提供多样性。这里给一个LightGBM的参考配置是我在比赛里反复调过、最终验证集F1最高的一组参数import lightgbm as lgb params { objective: binary, metric: auc, boosting_type: gbdt, learning_rate: 0.01, num_leaves: 64, max_depth: 7, min_child_samples: 20, feature_fraction: 0.7, bagging_fraction: 0.8, bagging_freq: 1, lambda_l1: 0.5, lambda_l2: 1.0, verbose: -1, seed: 2024, }num_leaves我故意调得比较大因为后面要靠融合来压制方差太保守的树模型反而容易欠拟合。注意训练时早停的策略也很关键验证集指标一停就拉倒别重复训练太久竞赛里时间比过度调参更宝贵。3.2 深度学习分支滑动窗口的时序视角树模型使用特征工程出来的一整块向量但其问题在于强行割裂了序列关系。所以我加了一条深度学习分支直接吃原始时间序列窗口。我尝试过两个结构LSTM Attention将滑动窗口内的电压、电流、温度作为输入经过两层LSTM后接attention池化输出一个序列嵌入向量再接分类层。1D CNN GRU用1D卷积先提取局部波形特征再用GRU捕捉长期依赖。效果上比纯LSTM略好一点主要优势在于训练速度更快且对短窗口的突跳型异常更敏感。深度模型这里我没有追求特别复杂的网络。因为异常电池样本数量本来就少太深的模型会直接过拟合训练噪声一堆。整个网络大概几百万参数训练50个epoch左右就够了。训练时还有个特殊处理就是使用了截断正态分布的数据增强对正常样本的电压曲线叠加一个极小幅度的随机噪声人为增加正常样本的多样性。这个操作在老手看来其实在异常检测任务里非常有价值因为正常样本的变化范围本来就该被模型充分认识。3.3 无监督重构分支用AutoEncoder抓“没见过的异常”竞赛里最好用的往往不是有监督模型而是无监督。因为异常模式不止训练集里的那几种测试集里很可能有新的未知异常。纯有监督模型面对新异常时完全无能为力所以异常检测比赛里AutoEncoder几乎是标配。我训练了一个结构非常简单但又很有效的AutoEncoder输入层单个滑动窗口的归一化序列。编码器两层全连接激活函数选ReLU中间维度压到32维。解码器两层全连接还原到原始输入维度。重构误差用MSE计算输入与重构输出的差异。正常样本模式单一AutoEncoder能在很少的训练轮次内就把它们记住并重构得很好异常样本因为“没见过”重构误差会明显偏大。我直接把重构误差作为一个额外特征丢给融合模型效果提升非常明显。这里有一个必须强调的细节训练AutoEncoder时只用训练集中的正常样本千万不要把异常样本放进去。否则模型连异常也能重构得不错重构误差就失去了判别能力。3.4 模型融合别瞎堆要有策略融合不是把所有输出做加权平均那么简单。关键点在于每个模型的预测应该具备不同的“视角”而不是同一个特征的变体。我最后融合的输入变量大致是这四类LightGBM输出的概率分数。CatBoost输出的概率分数。LSTMAttention输出的概率分数。AutoEncoder重构误差的归一化分数。融合方式我建议用两层结构第一层先把四个模型的输出都做Platt Scaling校准到同一个分布空间第二层用一个逻辑回归或浅层LightGBM去学习如何组合这些输出。简单说就是让元模型判断哪个分支在哪种样本上更值得信任。这个过程能带来多少提升以我的经验无脑平均大概能提升两到三个千分点而校准后带元模型的融合能提升五到八个千分点。差别非常显著。4. 训练与优化细节方案搭好了接下来就是训练过程的精细控制。竞赛里那些“分不高但看起来很忙”的队伍往往差就差在训练策略和验证策略没有对齐。4.1 验证集划分别让同电池的样本跨越折这块我要特别单独讲因为太重要了。电池数据不是独立同分布的数据同一个电芯产生的不同循环样本之间存在强关联。如果你按普通KFold随机划分同一个电芯的样本既出现在训练集又出现在验证集模型就相当于“偷看”了答案验证集分数会虚高得一塌糊涂线上表现却掉得厉害。正确做法是使用GroupKFold以电芯ID或电池ID作为分组依据。这样同一个电芯的所有样本不会同时分散到训练集和验证集验证结果才稳健。我另外还做了一个贴近线上分布的划分把时间靠后的电芯作为验证集模拟“预测未来”的真实场景。这样做能更早暴露模型在分布偏移上的问题。因为电池数据的采集时间顺序很重要异常的发生概率和传感器标定都会随时间漂移。4.2 样本不均衡别只知道过采样异常电池占比通常在5%以下。几万个正常样本对几百个异常样本直接训练会大概率退化成“全部预测正常”指标看似挺高其实根本没用。我实验了三种处理方式直接调整LightGBM的is_unbalance参数让它反向调节样本权重。这个最省事效果也不错。对异常样本做SMOTE过采样。在表格特征上是可行的但需要特别小心别在时序窗口上瞎插值否则容易生成不物理的样本。对异常样本分配较大的自定义样本权重比如用正常样本数除以异常样本数得到权重比。实际表现最稳的组合是is_unbalance开上同时给异常样本补一个1.5到2倍的额外权重系数。过采样在这个比赛里反而容易在验证集上虚高因为过采样很可能让模型把某个特定的噪声模式当作常见模式。4.3 后处理阈值和规则的临门一脚模型输出的概率本身不是最终答案你还需要把它变成判定结果。我在后处理环节做了两个重要操作一是阈值搜索。在验证集上遍历阈值找到F1最高或排序指标最优的阈值点。这个操作老生常谈但关键是搜索区间要画细一点步长设置到0.001否则容易错过最优区间。二是规则修正。经过对误报样本的分析我发现有一部分被预测为异常的样本其实它们在原始数据里对应的是“充电切换瞬间”的窗口属于电池正常工作必然出现的瞬时波动。这些样本确实有高重构误差但业务上不该被判定为异常。针对这种情况我加了一条规则如果某个窗口的前后20%时间点电压变化率都在正常范围内则将该样本的预测分数乘以0.7的惩罚系数。这个操作把误报率压低了差不多两个点而代价只是漏掉极少数真正异常的案例。后处理是纯业务经验的产物但恰恰是这类细微修正能让你在排行榜上超越好几个队。5. 实战中的坑与排查这段放到后面写是因为我在比赛过程中踩过太多坑有些坑甚至让我绕了整整两天路。为了让后来者少走弯路我把典型问题和排查思路整理成了速查表。5.1 常见问题速查表问题现象可能原因排查思路解决方案验证集F1很高线上分数反而低随机划分导致同电池样本泄漏检查是否按电芯分组划分改用GroupKFold或按时间划分所有预测概率都在0.9以上模型过拟合到噪声特征查看特征重要性和树深度调低num_leaves、增大正则AutoEncoder重构误差无区分度异常样本参与了训练确认训练集只用正常样本过滤异常样本后重新训练LightGBM和CatBoost结果几乎一致模型输入特征完全相同对比两个模型的特征重要性给两个模型分别使用不同特征子集阈值怎么调都不能提升排名评价指标理解错误仔细阅读赛题的评分公式按排序指标重新设计优化目标深度模型训练波动极大学习率过高或样本比例失衡观察每个epoch损失曲线降低学习率并增加warmup5.2 特征泄漏的典型案例竞赛里最隐蔽的错误是特征泄漏。我遇到过一个很典型的泄漏特征工程里生成了一个叫“当前循环相对上一个循环的电压差异”的特征看起来特别合理但在构造这个特征时我用到了整个测试周期之后的数据相当于在预测时偷看了未来的信息。更常见的泄漏是标准化和数据缩放完成在全量数据上。如果先对整个训练加测试数据一起做StandardScaler再划分训练验证验证集的分数会被抬高。正确的做法是先只对训练集拟合缩放器参数再应用到验证集和测试集。竞赛圈子里有个铁律所有数据预处理转换器的fit只能在训练折内部完成。这条规则违反了前面所有模型搭建都白搭。5.3 过拟合的信号与对策怎么判断自己过拟合了最简单的办法就是看训练集和验证集指标差距。LightGBM如果训练集AUC接近0.999验证集只有0.85这个差值已经说明模型在死记硬背特征组合而不是在学通用规律。应对过拟合我一般按下面几步走增加leaf惩罚权重和L2正则项。降低leaves数量迫使模型学习更稀疏的模式。增加特征采样率调节系数减少每棵树的特征选择空间。提前停止轮次别让它把最后几个百分点的训练损失也硬吃了。减少或剔除重要度很低的长尾特征让模型专注核心信号。在深度模型那边除了正则我还习惯用early stopping并保存验证集表现最好的checkpoint而不是最后一个epoch的权重。同理学习率衰减策略用余弦退火比固定学习率稳得多。6. 实操心得与扩展建议这段作为结尾想说些方案之外但同样值得琢磨的东西。6.1 让方案稳定的关键心法我这次拿到第二名的体验是比赛方案的上限不是由某个单独模型的性能决定的而是由整套方案的稳定性决定的。你永远不知道测试集里有多少新异常模式线上分数总有波动如果模型对特征或阈值的微小变化极度敏感那排名就变成了抽奖。要让方案稳定我总结三条心法多视角印证同一个异常最好能被至少两种不同类型的模型识别出来。这样融合后不会被单一模型的错误带偏。小而稳优于大而玄一个复杂度极低的模型只要特征质量过硬往往比一个精巧复杂但训练不充分的大模型更可靠。快速迭代闭环每次改动都记录验证集和线上分数对比哪怕一个特征提升了0.001也留档。这样可以清楚知道每一次变化是向上还是向下。6.2 从比赛到真实业务的迁移如果把这个方案迁移到真实场景遇到的问题会更多。比赛里基础模型可以直接用标签训练但在实际业务中异常标签往往需要维修记录或人工标记来积累数据标注成本极高。真实场景里我更推荐把这个方案改造成“召回研判”模式召回层用AutoEncoder重构误差排序把重构误差排名前5%的样本捞出来。研判层用LightGBM等有监督模型对召回样本做细粒度分类。人工复核保留阈值调整按钮让一线的维护专家根据实际检修结果持续校准模型。这种模式的好处是它不指望模型一次性把判断做对而是通过“系统找人 人校验系统”的循环慢慢把规则沉淀到模型里也把误报带来的信任成本降到最低。6.3 如果重来我会优化什么最后的最后说点实在的。如果再让我重新打一次这个比赛我会把更多时间分配在深度模型的序列建模上。表格特征虽然让我拿了第二名但从排行榜头部队伍的输出特征来看真正拉开差距的很可能不是特征数量而是对时序上下文建模的精细度。我会尝试给每个电芯的电化学阻抗谱建模然后把阻抗谱特征和时序特征融合成多模态输入。至于能不能有效果坦白说没有做实验前谁也说不准但方向上肯定值得一试。竞赛就是这样永远有下一个可以优化的角落这也是它之所以迷人的原因。
返回列表