3. 数据采集与预处理:传感器数据采集、缺失值处理、异常值检测、数据归一化与标准化
做SOC预测这些年,我踩过最大的坑是什么?不是模型选错了,而是数据预处理没做好。你想想看,传感器采集回来的原始数据,就像刚从泥里挖出来的土豆——不洗干净,谁敢直接下锅?
这一章,咱们就聊聊怎么把这堆“脏数据”收拾得服服帖帖。我保证,看完你就能上手干活。
3.1 传感器数据采集:从硬件到数字的“第一公里”
先说采集。SOC预测常用的传感器就那么几种:电压传感器、电流传感器、温度传感器。嗯,听起来简单,但实际采集时问题一堆。
采样频率怎么定?
我个人习惯是:先看电池的动态特性。锂电池的电压变化相对缓慢,1Hz的采样率基本够用。但如果你做的是动力电池,急加速时电流变化很快,建议提到10Hz以上。
传感器标定
传感器出厂时都有误差,有的还很大。我建议你拿到新传感器后,先做个简单的标定:用已知电压源测一下,看看偏差多少。记录下来,后面预处理时直接补偿。
# 一个简单的标定补偿示例
def calibrate_voltage(raw_voltage, offset=0.02, scale=1.001):
"""
raw_voltage: 传感器原始读数
offset: 零点偏移(实测得到)
scale: 增益系数(实测得到)
"""
calibrated = (raw_voltage - offset) * scale
return calibrated
3.2 缺失值处理:别让“空洞”毁了你的模型
采集过程中,数据丢失是家常便饭。通信中断、传感器故障、存储异常……原因多了去了。遇到缺失值怎么办?
三种常见策略:
- 直接删除: 如果缺失比例很小(<5%),而且缺失是随机的,删了就删了。简单粗暴,但有效。
- 前向填充: 用上一个有效值填充。适合电压、温度这种变化缓慢的参数。我在项目中经常用这个方法,效果不错。
- 插值法: 线性插值或样条插值。适合电流这种波动较大的数据。但要注意,插值会引入人为误差,别过度使用。
# 缺失值处理示例
import pandas as pd
import numpy as np
def handle_missing(df, column, method='ffill', max_gap=5):
"""
df: 数据框
column: 要处理的列名
method: 'ffill' 前向填充, 'linear' 线性插值
max_gap: 最大连续缺失数,超过则丢弃
"""
if method == 'ffill':
df[column] = df[column].ffill()
elif method == 'linear':
df[column] = df[column].interpolate(method='linear')
# 丢弃连续缺失过多的片段
mask = df[column].isna().groupby(df[column].notna().cumsum()).transform('count') > max_gap
df.loc[mask, column] = np.nan
df = df.dropna(subset=[column])
return df
3.3 异常值检测:揪出那些“捣乱分子”
传感器偶尔会抽风,蹦出个离谱的值。比如电压突然跳到100V,或者温度变成-200°C。这些异常值如果不处理,模型会被带偏。
怎么检测?
- 3σ原则: 数据服从正态分布时,超过均值±3倍标准差的值视为异常。简单,但要求数据分布不能太偏。
- IQR方法: 四分位距法。用Q1-1.5*IQR和Q3+1.5*IQR作为边界。对非正态分布更鲁棒。我个人更推荐这个。
- 领域知识: 比如锂电池电压不会超过4.2V,低于2.5V基本就是过放了。直接设个硬阈值,比啥算法都管用。
# IQR异常值检测
def detect_outliers_iqr(data, factor=1.5):
Q1 = np.percentile(data, 25)
Q3 = np.percentile(data, 75)
IQR = Q3 - Q1
lower_bound = Q1 - factor * IQR
upper_bound = Q3 + factor * IQR
outliers = (data < lower_bound) | (data > upper_bound)
return outliers
3.4 数据归一化与标准化:让所有特征“平起平坐”
电压、电流、温度,量纲完全不同。电压是伏特(3-4V),电流是安培(可能上百A),温度是摄氏度(-20到60°C)。如果不做归一化,模型会天然偏向数值大的特征。说白了,就是电流会把电压“欺负”得死死的。
两种主流方法:
| 方法 | 公式 | 适用场景 | 我的建议 |
|---|---|---|---|
| Min-Max归一化 | x' = (x - min) / (max - min) | 数据有明确边界,如电压[2.5, 4.2] | SOC预测中,电压和温度推荐用这个 |
| Z-score标准化 | x' = (x - μ) / σ | 数据分布近似正态,无明确边界 | 电流数据常用,因为电流波动大,没有固定范围 |
# 归一化与标准化示例
from sklearn.preprocessing import MinMaxScaler, StandardScaler
# 假设 train_data, test_data 已经准备好
# 电压和温度用Min-Max
scaler_voltage = MinMaxScaler(feature_range=(0, 1))
train_data['voltage_norm'] = scaler_voltage.fit_transform(train_data[['voltage']])
test_data['voltage_norm'] = scaler_voltage.transform(test_data[['voltage']])
# 电流用Z-score
scaler_current = StandardScaler()
train_data['current_std'] = scaler_current.fit_transform(train_data[['current']])
test_data['current_std'] = scaler_current.transform(test_data[['current']])
3.5 本章知识体系:一张图看懂预处理流程
说了这么多,咱们用一张图把整个流程串起来。这是我做项目时自己画的,后来成了团队的标准流程。
嗯,这张图基本概括了咱们这一章的核心内容。从传感器采集开始,到缺失值处理、异常值检测,再到归一化标准化,最后划分数据集。每一步都有讲究,顺序也不能乱。
我记得第一次做SOC项目时,图省事跳过了异常值检测,结果模型训练出来,预测误差大得离谱。后来排查了两天才发现,是传感器偶尔的毛刺在作怪。从那以后,我再也不敢偷懒了。
数据预处理这件事,说白了就是“磨刀不误砍柴工”。你花80%的时间把数据收拾干净,后面建模可能只需要20%的时间。反过来,数据一团糟,模型再先进也白搭。
- 传感器采集:注意采样频率和标定
- 缺失值处理:前向填充最常用,连续缺失多则丢弃
- 异常值检测:IQR方法比3σ更鲁棒,结合领域知识设阈值
- 归一化/标准化:电压温度用Min-Max,电流用Z-score
- 所有预处理参数只从训练集计算
公众号:蓝海资料掘金营,微信deep3321