3、数据预处理:清洗、去重、异常值处理

数据预处理,说白了就是给设备画像「洗菜切菜」。你从现场采集回来的数据,脏、乱、差,什么都有。我见过太多项目,模型算法选得再好,数据一塌糊涂,最后全白搭。

这一章,咱们就聊聊怎么把原始数据收拾得服服帖帖。

3.1 数据清洗:把垃圾倒掉

数据清洗,核心就三件事:补缺失、纠错误、整格式。

3.1.1 缺失值处理

设备传感器偶尔掉线,或者传输丢包,数据就缺了一块。怎么办?

  • 直接删除:缺失比例小于5%,且是随机缺失,删了影响不大。
  • 均值/中位数填充:连续型数值,比如温度、压力,用前后均值补上。
  • 前向/后向填充:时间序列数据,用上一个有效值填充。我习惯用 ffill()。
  • 模型预测填充:缺失值很重要,就用KNN或回归模型预测。但别滥用,计算量太大。
我的习惯:先看缺失比例。超过30%的字段,我直接扔掉。低于5%的,用均值填充。中间那档,用前向填充最省事。

3.1.2 格式统一

同一个设备,不同时间段的温度单位可能不一样。有的用摄氏度,有的用华氏度。这必须统一。

# 温度统一转成摄氏度
def temp_convert(value, unit):
    if unit == 'F':
        return (value - 32) * 5 / 9
    elif unit == 'C':
        return value
    else:
        return None

df['temperature'] = df.apply(lambda x: temp_convert(x['temp_value'], x['temp_unit']), axis=1)

时间格式也得统一。我遇到过最坑的,同一个设备,时间戳有的用 YYYY-MM-DD HH:MM:SS,有的用 YYYY/MM/DD。不统一,后面排序、聚合全乱套。

3.2 数据去重:别让重复数据骗了你

设备数据重复,原因很多:网络重传、采集程序bug、人工误操作。重复数据会让统计结果失真,比如平均故障间隔时间(MTBF)算出来偏大。

3.2.1 完全去重

所有字段都一样,直接删掉。

df.drop_duplicates(inplace=True)

3.2.2 部分去重

关键字段相同,但时间戳不同。比如同一台设备,同一时刻上报了两次数据。这种情况,保留第一条或最后一条。

df.drop_duplicates(subset=['device_id', 'timestamp'], keep='first', inplace=True)
我曾经踩过的坑:有一次做振动分析,重复数据没去干净,导致频谱里出现了虚假的倍频成分。排查了两天才发现,原来是同一个传感器数据被采集程序重复写入了三次。从那以后,我每次做预处理,第一件事就是检查重复率。

3.3 异常值处理:揪出捣乱的「坏数据」

异常值,就是那些明显偏离正常范围的数据点。可能是传感器故障、通信干扰,或者设备真的出了异常。但注意,异常值不一定是错误值——设备故障前的剧烈波动,恰恰是我们要捕捉的信号。

3.3.1 统计方法

方法 原理 适用场景
3σ原则 超出均值±3倍标准差的数据视为异常 数据近似正态分布
箱线图(IQR) 超出Q1-1.5×IQR或Q3+1.5×IQR的数据视为异常 数据分布偏态,或不知道分布形态
Z-Score 计算每个数据点的Z分数,超过阈值(通常3)视为异常 数据量较大,需要标准化处理

我个人更偏爱箱线图法。为什么?因为它不受极端值影响,鲁棒性好。你想想看,如果数据本身就有几个极端值,用3σ原则算出来的均值和标准差都被带偏了,反而检测不出真正的异常。

# 箱线图法检测异常值
Q1 = df['vibration'].quantile(0.25)
Q3 = df['vibration'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

df['is_outlier'] = (df['vibration'] < lower_bound) | (df['vibration'] > upper_bound)

3.3.2 时序方法

设备数据是时间序列,相邻数据点之间有关联。这时候,可以用移动平均或指数平滑来检测异常。

# 移动平均法检测异常
df['rolling_mean'] = df['temperature'].rolling(window=5).mean()
df['rolling_std'] = df['temperature'].rolling(window=5).std()
df['is_anomaly'] = abs(df['temperature'] - df['rolling_mean']) > 3 * df['rolling_std']
关键区别:统计方法看的是全局分布,时序方法看的是局部波动。对于设备画像,我建议两种方法结合使用。先用箱线图筛掉明显的传感器故障数据,再用移动平均法捕捉设备状态突变。

3.4 知识体系总览

下面这张图,把数据预处理的整个流程串起来了。你可以把它当作操作手册,每次做预处理前看一眼。

数据预处理流程总览 原始采集数据 数据清洗 缺失值处理 格式统一 纠错修正 数据去重 完全去重 部分去重 异常值处理 输出:干净、一致、无重复、异常标记的标准化数据集

3.5 处理策略总结

数据预处理没有银弹。不同场景,策略不同。我整理了一个决策表,你可以对照着用。

数据类型 常见问题 推荐处理方式 注意事项
连续型数值(温度、压力) 缺失、跳变、漂移 前向填充 + 箱线图检测 跳变可能是真实故障,别一刀切
离散型状态(开关、档位) 重复、非法值 完全去重 + 枚举校验 非法值直接置为NaN或前向填充
时间戳 格式不统一、时区混乱 统一转成UTC时间戳 注意夏令时和闰秒
文本型(设备型号、厂商) 大小写不一致、拼写错误 统一小写 + 模糊匹配 建立标准字典表,自动映射
重要提醒:异常值处理,一定要保留原始数据副本。我见过有人直接覆盖原字段,结果发现误判了,想恢复都恢复不了。我的做法是:新增一列 is_anomaly 标记,而不是直接删除或修改原始值。这样,模型训练时可以选择是否使用异常标记样本,灵活得多。

数据预处理,看似繁琐,但它是设备画像的基石。你花80%的时间做数据准备,后面20%的时间建模就够了。反过来,数据没处理好,后面花200%的时间也救不回来。