拿到几百行电池循环数据,你第一步会做什么?
【A】直接画图 📈
【B】先清洗再动手 🧹
【C】先看字段说明 📋
- 本系列第02篇培训教材:带你掌握电池数据工程的第一步—从 CSV 读懂循环测试数据、做清洗、画容量衰减曲线。
- 本文将演示:①用 pandas 读取 CSV 并看懂字段;②处理缺失值与离群点;③计算 SOH 并绘制容量衰减曲线、识别 80% 寿命阈值。
- 代码已在本环境实测运行,附复现环境卡与真实运行验证记录,可离线复现。
- 核心观点:"垃圾进,垃圾出"——数据清洗的质量,直接决定后面所有 AI 模型的可靠性。
一、问题的起点:几百行循环数据,怎么下手?
上一篇你搭好了环境。现在面对真实问题:实验给了你几百次循环的放电容量数据,怎么直观看出电池衰减成什么样?
但现实中的原始数据从来不是干净的: - 有缺失值(某天设备断点,容量是空的) - 有离群点(传感器抖动、记录异常,出现离谱数值) - 有噪声(测量本身的随机波动)
如果不管这些直接画图、直接喂给模型,结果是:曲线恶心、模型被带偏。所以数据清洗不是可选项,是必选项。
二、读数据:pandas 一眼看清字段
用上一篇的"隔离环境",先读入数据并看一眼全貌(.shape、.head()、.info()):
import pandas as pd df = pd.read_csv('battery_cycle_data.csv') print("形状 shape:", df.shape) # (行数, 列数) print("前5行:\n", df.head()) print("数据类型与缺失:\n", df.info())数据字段说明(本例为模拟,真实数据字段类似): -cycle:循环次数(第几次充放电) -capacity_ah:该次循环的放电容量(Ah),体检电池健康的关键指标-voltage_v:电压(V)
📌 真实工程常用NASA 电池老化数据集 / 牛津电池数据集。本篇为保证读者离线也能复现,用固定 seed 生成本地 CSV 演示流程;你完全可把
read_csv换成真实数据路径,处理逻辑不变。
三、数据清洗:先治脏数据
这是本篇最值钱的 20 行代码。核心三步:处理缺失 → 处理离群 → 归一化。
import numpy as np df = pd.read_csv('battery_cycle_data.csv') # 1) 缺失值:前向填充(用上一个有效值补)+ 中位数兜底 if df['capacity_ah'].isna().any(): df['capacity_ah'] = df['capacity_ah'].ffill().fillna(df['capacity_ah'].median()) # 2) 离群点:超出 均值±3σ 的替换为中位数(简单稳健,适合教学) cap = df['capacity_ah'].copy() mean, std = cap.mean(), cap.std() mask = (cap < mean - 3*std) | (cap > mean + 3*std) print(f"检测到离群点 {mask.sum()} 个") cap[mask] = cap.median() df['capacity_ah'] = cap # 3) 归一化 SOH:= 当前容量 / 初始最大容量 df['soh'] = df['capacity_ah'] / df['capacity_ah'].max()为什么这样处理?-缺失用 ffill:容量是连续物理量,用相邻值补比用均值合理。 -离群用 3σ 判定 + 中位数替换:3σ 之外的极值很可能是异常,中位数对离群稳健(不被离群本身拉偏)。 -SOH 归一化:把容量换算成 0~1 的健康度,统一不同电芯的对比尺度。
四、画图:容量衰减曲线 + 80% 寿命线
清洗完就能画能看懂的曲线了—并加上"80% 阈值"这条行业通用寿命红线(当 SOH ≤ 0.8 通常视为退役阈值):
import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(9,5)) ax.plot(df['cycle'], df['soh'], lw=1.8, color='tab:blue', label='清洗后SOH') ax.axhline(0.8, color='red', ls='--', lw=1, label='80%寿命阈值') ax.set_xlabel('循环次数'); ax.set_ylabel('SOH') ax.set_title('电池容量衰减曲线(清洗后)') ax.legend(); ax.grid(alpha=0.3) fig.tight_layout(); fig.savefig('fig_article02_curve.png', dpi=120)五、真实运行验证记录
以下为本脚本在测试环境的真实输出:
已生成 data/battery_cycle_data.csv, 行数 400 读取原始数据 shape: (400, 3) 检测到离群点 1 个(1 处) === 运行验证记录 === 清洗后 SOH 最小值: 0.7129 清洗后 SOH 最大值: 1.0 达到80%阈值时的循环次数: 282 清洗后空值数: 0观察结论: - 400 次循环数据,清洗后无空值、离群点被处理; - SOH 从 1.0 衰减到 0.71,在第 282 个循环跌破 80% 阈值; - 这段"282 次循环到寿"的信息,是后续做 SOH 预测、寿命估计的监督标签——下一篇就教你把它做成可复用函数。
六、环境卡
依赖清单(锁版本)
python==3.13.15 numpy==2.4.6 pandas==3.0.5 matplotlib==3.11.0 jupyter验证命令与预期
conda activate battery-ai python demo_02.py预期:几秒跑完无报错,输出含"达到80%阈值时的循环次数: 282",并生成fig_article02_curve.png。
常见报错自查表
| 报错 | 原因 | 解法 |
|---|---|---|
FileNotFoundError | 数据文件路径不对 | 把battery_cycle_data.csv和脚本放同一目录 |
KeyError: 'capacity_ah' | 列名不一致 | print(df.columns)核对实际列名 |
numpy.nan误报 | 缺失未处理 | 确保先跑缺失值清洗步骤 |
| 中文字体方块 | 未配置字体 | 按第01篇自查表加字体 |
七、练习
- 改衰减速率:把
0.0007改成0.0010,看 80% 阈值提前到第几个循环。 - 刻意不清洗:注释掉离群点处理,观察曲线出现"毛刺",理解清洗的必要性。
- 换真实数据:下载任公开电池数据集,仅改
read_csv路径,验证清洗画图流程是否通用。
验收标准:能独立讲出"缺失值/离群点/SOH"各自为什么这样处理;能画出带 80% 阈值的衰减曲线并读出到寿循环数。
八、Q&A
Q1:为什么用 3σ 判离群,会不会误删好数据?A:3σ 是常用经验值,对服从近似正态的容量数据较稳健。若担心误删,可改用分位数法(如 IQR)或先画分布图观察。教学选用 3σ 简单直观。
Q2:缺失值为什么用 ffill 而不是直接删掉那行?A:容量是随时间连续变化的物理量,删行会破坏序列结构的连续性(尤其后续要按顺序训练时序模型),ffill 用相邻值补更合理。
Q3:模拟数据和真实 NASA 数据差别大吗?A:模拟数据信号形态近似、便于离线复现;真实数据有更复杂的非线性衰减、容量回升等现象。本例演示的是通用处理流程,换真实数据逻辑不变。
Q4:SOH 一定要除以最大值吗?A:常见做法是除以额定容量或初始容量。教学用最大值归一化更稳健(避免初值离群影响)。工程上按电池厂商标定为准。
Q5:清洗会影响最终 SOH 预测精度吗?A:会,而且影响很大。脏数据会污染特征和标签。清洗得当通常能明显提升模型稳定性和可复现性。
九、下一篇预告
第03篇:把今天这段"清洗-画图"逻辑封装成可复用函数,用 AI 工具帮你批量处理几百个电芯的文件——告别复制粘贴,迈向工程化。
AI 工具使用心得
本篇用 AI 生成数据清洗(ffill + 3σ)的稳健写法、并设计"生成带脏数据的模拟CSV"来演示清洗前后的对比——让 AI 造了一个可用来教学的'脏数据样例',比自己手动造更高效、更贴近真实。效率点:写演示数据+清洗逻辑一次成型。踩坑:先想让缺失值np.nan参与运算报错,明确要先做 isna() 检查再处理。
代码声明:本文代码与数据均为培训教学示例,用于演示数据清洗与分析方法,仅供学习复现与上手练习;不构成任何生产级软件、BMS 算法或商业产品实现建议。用于真实电池管理系统或量产场景时须另行充分验证,作者不对因环境差异、误用或改编造成的后果负责。
本文为技术科普与工程编程教程,不构成任何投资、购买或商业决策建议。文中涉及的技术路线、代码实现与运行环境信息可能存在更新,请以原文、最新官方文档及厂商最新发布为准。