第1章:数据预处理实战——打好基础,少走弯路
大家好,我是老张。在故障预测这个行当摸爬滚打了十几年,我最大的体会就是:数据预处理做得好,模型成功一半。这话一点都不夸张。你想想看,原始数据就像刚从矿里挖出来的矿石,杂质多、形态乱,直接拿去训练模型,结果可想而知。
今天这一章,咱们就聊聊数据预处理的四个核心环节:缺失值处理、异常值检测、数据标准化与归一化、时间序列重采样。这些都是我每天都会用到的基本功,也是很多新手容易踩坑的地方。
1.1 缺失值处理——别让"空"坑了你
我在项目中遇到过最头疼的事,就是传感器数据突然断档。设备还在转,数据却没了。这种缺失值如果不处理,模型会学出"幻觉"来。
缺失值处理,说白了就三种思路:删、填、猜。
1.1.1 直接删除
如果缺失比例很小(比如不到5%),而且缺失是随机的,直接删掉最省事。但要注意——千万别删成片的数据。我曾经有个项目,连续删了30%的行,结果模型训练出来完全不准。后来才发现,那些缺失值其实集中在某个故障模式里,删掉等于把关键信息丢了。
1.1.2 填充法
填充是最常用的方法。我个人习惯按这个顺序来:
- 均值/中位数填充:数值型数据,分布对称用均值,有偏态用中位数
- 前向/后向填充:时间序列数据,用前一时刻的值填充,这叫"ffill"
- 插值法:线性插值、样条插值,适合变化平滑的数据
import pandas as pd
import numpy as np
# 生成示例数据
df = pd.DataFrame({
'温度': [25, np.nan, 27, 28, np.nan, 30],
'振动': [0.5, 0.6, np.nan, 0.8, 0.9, np.nan]
})
# 均值填充
df['温度'].fillna(df['温度'].mean(), inplace=True)
# 前向填充(时间序列常用)
df['振动'].fillna(method='ffill', inplace=True)
print(df)
1.2 异常值检测——揪出"捣乱分子"
异常值是什么?就是那些明显偏离正常范围的数据点。在故障预测里,异常值可能是传感器误报,也可能是故障的前兆。怎么区分?这就是检测方法要解决的问题。
1.2.1 3σ 法则
这个方法基于正态分布。数据在均值±3个标准差范围内的概率是99.7%,之外的就算异常。简单粗暴,但好用。
def detect_outliers_3sigma(data):
mean = np.mean(data)
std = np.std(data)
lower = mean - 3 * std
upper = mean + 3 * std
outliers = (data < lower) | (data > upper)
return outliers
# 示例
data = np.random.normal(50, 10, 1000)
data[0] = 120 # 人为加入异常
outliers = detect_outliers_3sigma(data)
print(f"检测到 {sum(outliers)} 个异常值")
1.2.2 IQR 方法
IQR(四分位距)法不依赖正态分布假设,更稳健。它把数据分成四份,取Q1(25%分位)和Q3(75%分位),IQR = Q3 - Q1。异常值定义为小于Q1-1.5×IQR或大于Q3+1.5×IQR的点。
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 3σ | 正态分布数据 | 计算简单,理论成熟 | 对偏态数据不敏感 |
| IQR | 任意分布数据 | 稳健,不受极端值影响 | 对样本量有要求 |
1.3 数据标准化与归一化——让不同量纲的数据"对话"
你想想看,温度是几十度,振动是零点几毫米/秒,压力是几兆帕。这些数据直接放一起,模型会天然偏向数值大的特征。所以我们需要标准化或归一化。
1.3.1 Z-score 标准化
公式很简单:z = (x - μ) / σ。处理后数据均值为0,标准差为1。适合数据近似正态分布的情况。
1.3.2 Min-Max 归一化
公式:x' = (x - min) / (max - min)。把数据压缩到[0,1]区间。适合数据有明确边界的情况。
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# 标准化
scaler_std = StandardScaler()
data_std = scaler_std.fit_transform(df[['温度', '振动']])
# 归一化
scaler_mm = MinMaxScaler()
data_mm = scaler_mm.fit_transform(df[['温度', '振动']])
1.4 时间序列重采样——对齐时间轴
故障预测的数据往往来自不同传感器,采样频率不一样。有的每秒采一次,有的每分钟采一次。不重采样,根本没法分析。
1.4.1 降采样
从高频到低频。比如把1秒的数据聚合成1分钟的数据。常用聚合函数:均值、中位数、最大值、最小值。
1.4.2 升采样
从低频到高频。比如把1分钟的数据插值到1秒。这需要小心——插值出来的数据是"假的",不能太当真。
# 生成时间序列数据
dates = pd.date_range('2024-01-01', periods=100, freq='5min')
df_ts = pd.DataFrame({'value': np.random.randn(100)}, index=dates)
# 降采样到1小时
df_hourly = df_ts.resample('1H').mean()
# 升采样到1分钟(线性插值)
df_minutely = df_ts.resample('1min').interpolate(method='linear')
print("原始数据量:", len(df_ts))
print("降采样后:", len(df_hourly))
print("升采样后:", len(df_minutely))
好了,这一章的内容就到这里。数据预处理看起来琐碎,但每一步都关系到最终模型的成败。我个人觉得,花在预处理上的时间,永远值得。
公众号:蓝海数据掘金营,微信deep3321