第3章:Python数据处理基础
做电池建模这几年,我越来越觉得:数据处理能力,直接决定了模型的上限。你想想看,再漂亮的等效电路模型,喂进去的数据是脏的、乱的、时间戳对不齐的,那结果能看吗?
这一章,咱们就聊聊Python里最常用的两个库——NumPy和Pandas。说白了,就是教会你怎么把电池测试数据收拾得服服帖帖。
3.1 NumPy数组操作:电池数据的"集装箱"
NumPy的数组,我习惯叫它"集装箱"。为啥?因为它能装大量数据,而且装卸效率极高。
先看个最简单的例子。假设你有一组电池的电压数据:
import numpy as np
# 创建一维数组
voltage = np.array([3.7, 3.8, 3.9, 4.0, 4.1])
print(voltage)
# 输出:[3.7 3.8 3.9 4.0 4.1]
# 创建二维数组(比如:行=时间点,列=不同电芯)
battery_data = np.array([
[3.7, 3.8, 3.9],
[3.6, 3.7, 3.8],
[3.5, 3.6, 3.7]
])
print(battery_data.shape)
# 输出:(3, 3) —— 3行3列
嗯,这里要注意:数组的维度一定要对齐。我在项目中遇到过,有人把不同长度的数据硬塞进一个数组,结果报错不说,还找半天bug。
3.1.1 数组切片与索引
电池数据通常按时间排列。你想取某段时间的数据?切片就对了:
# 取第2行到第4行(索引从0开始)
subset = battery_data[1:3, :]
print(subset)
# 取所有行的第1列(比如:所有时间点的电压)
voltage_col = battery_data[:, 1]
print(voltage_col)
3.1.2 数组运算:向量化操作
电池数据处理中,最常用的就是批量运算。比如,把电压从伏特转为毫伏:
voltage_mv = voltage * 1000
print(voltage_mv)
# 输出:[3700. 3800. 3900. 4000. 4100.]
你看,不用写循环。这就是NumPy的向量化操作,快得飞起。
再比如,计算SOC(荷电状态)的近似值:
# 假设电压范围3.0V~4.2V对应SOC 0%~100%
soc = (voltage - 3.0) / (4.2 - 3.0) * 100
print(soc)
# 输出:[58.33 66.67 75. 83.33 91.67]
3.2 Pandas DataFrame读写:数据表格的瑞士军刀
NumPy处理数值很爽,但电池数据往往带着时间戳、电芯编号、测试条件这些"标签"。这时候,Pandas的DataFrame就派上用场了。
我个人觉得,DataFrame就像Excel表格的升级版——能自动对齐、能处理缺失值、还能做各种筛选。
3.2.1 读取CSV文件
电池测试数据最常见的格式就是CSV。读取方法很简单:
import pandas as pd
# 读取电池测试数据
df = pd.read_csv('battery_test_data.csv')
print(df.head()) # 查看前5行
但这里有个坑——时间戳的解析。很多测试设备输出的时间格式五花八门:
# 指定时间列,并解析为datetime类型
df = pd.read_csv('battery_test_data.csv',
parse_dates=['timestamp'],
index_col='timestamp')
print(df.index)
# 输出:DatetimeIndex(['2024-01-01 10:00:00', ...])
3.2.2 数据预览与基本信息
拿到数据后,我通常会先做这几步:
# 查看数据基本信息
print(df.info())
# 查看统计摘要
print(df.describe())
# 查看列名
print(df.columns)
你想想看,如果数据有几十万行,不先看看基本信息,直接上手分析,很容易出问题。
3.3 数据清洗与插值:把"脏数据"变干净
电池测试数据,几乎没有一次是干净的。传感器漂移、通信中断、人为操作失误……各种情况我都遇到过。
3.3.1 处理缺失值
最常见的缺失值表现是NaN。处理方法有三种:
# 方法1:删除含有缺失值的行
df_clean = df.dropna()
# 方法2:用前一个有效值填充(适合电压、电流这种连续变化的数据)
df_filled = df.fillna(method='ffill')
# 方法3:用线性插值(我个人最推荐)
df_interpolated = df.interpolate(method='linear')
3.3.2 异常值检测
电池数据里,偶尔会出现离谱的值。比如电压突然跳到10V——这明显是传感器故障。
# 基于3σ原则检测异常值
mean = df['voltage'].mean()
std = df['voltage'].std()
df_valid = df[(df['voltage'] > mean - 3*std) &
(df['voltage'] < mean + 3*std)]
嗯,这里要注意:3σ原则假设数据服从正态分布。电池充放电数据往往不服从正态分布,所以我会结合物理常识来判断。比如,锂电池电压不可能超过4.3V,低于2.5V。
3.4 时间序列处理:对齐时间轴
电池测试中,不同设备采集的数据,时间戳往往不同步。比如,电压采集器每1秒记录一次,电流采集器每0.5秒记录一次。这时候就需要重采样。
3.4.1 重采样
# 将数据重采样到1秒间隔,取平均值
df_resampled = df.resample('1S').mean()
# 如果数据有缺失,用插值填充
df_resampled = df.resample('1S').interpolate()
3.4.2 时间偏移与差分
计算电池的容量变化,常用到差分:
# 计算电流的积分(近似容量变化)
df['capacity_change'] = df['current'].cumsum() * dt # dt是时间间隔
# 计算电压变化率
df['dv_dt'] = df['voltage'].diff() / dt
3.5 本章知识体系
下面这张图,是我梳理的数据处理流程。你可以把它当作操作手册:
这张图我画了好几次才满意。你看,从数据读取到模型输入,每一步都环环相扣。而且,实际项目中经常需要回溯——比如清洗时发现数据格式有问题,就得回去重新读取。
3.6 本章小结
这一章的内容,说白了就是三件事:
- NumPy:处理数值数组,做批量运算
- Pandas:处理带标签的表格数据,尤其是时间序列
- 数据清洗与插值:把脏数据变成可用的干净数据
我个人觉得,数据处理占整个电池建模工作量的60%以上。模型本身可能就几行代码,但数据准备能折腾好几天。所以,别嫌这些基础操作啰嗦——它们是你后续建模的基石。
下一章,咱们就开始搭建第一个等效电路模型了。到时候你会发现,数据准备得越充分,模型跑起来越顺手。