4. 失效数据基础

数据采集回来,十有八九是脏的。这是我干失效分析这些年最深的体会。

传感器掉线、通信丢包、人为误操作……原始数据里什么妖魔鬼怪都有。你直接拿这些数据去建模,结果就是 garbage in, garbage out。所以,数据清洗不是锦上添花,是必修课。

这一章,我把几个最常用的预处理手段掰开揉碎讲清楚。都是我在产线上踩过坑、填过土之后沉淀下来的东西。

4.1 缺失值处理

缺失值是最常见的问题。说白了,就是某个时间点或某个字段,数据没了。

核心原则: 先搞清楚缺失机制,再选处理方法。不要上来就填均值。

4.1.1 缺失机制分类

类型 含义 举例
MCAR 完全随机缺失 传感器偶尔被鸟撞了一下,随机丢包
MAR 随机缺失(依赖其他变量) 高温工况下,某个温度探头容易失效
MNAR 非随机缺失(依赖自身) 压力过高时,压力传感器直接烧毁

我个人习惯,拿到数据先做缺失值可视化。用热图或者条形图看一眼缺失分布,心里就有数了。

4.1.2 常用处理方法

  • 直接删除: 缺失比例小(<5%),且是MCAR。简单粗暴,但样本少时慎用。
  • 均值/中位数填充: 数值型变量,分布对称用均值,有偏态用中位数。我在项目里遇到过,填充均值后模型反而变差了——因为破坏了原始分布。
  • 前向/后向填充: 时间序列数据常用。比如传感器在10:00:01有值,10:00:02缺失,用前一个值顶上去。适合缓慢变化的物理量。
  • 插值法: 线性插值、样条插值。适合连续变化的数据,比如温度、压力曲线。
  • 模型预测填充: 用其他字段做回归或KNN预测缺失值。精度高,但计算量大。
我的经验: 失效分析场景下,我优先用前向填充+线性插值组合。既保留了时序连续性,又不会引入太多人为偏差。

4.2 异常值检测

异常值,就是那些明显偏离正常范围的点。在失效分析里,异常值往往就是故障的前兆。所以,别急着删,先看看它是不是宝贝。

4.2.1 3σ 法则(拉依达准则)

假设数据服从正态分布。均值 ± 3倍标准差以外的点,视为异常。

import numpy as np

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

这个方法的缺点很明显——它对正态性要求高。如果数据本身有偏态,或者有多个峰值,3σ 会漏检或误检。我记得有一次分析振动数据,3σ 把正常的高频波动全标成了异常,差点把工程师带沟里去。

4.2.2 IQR 方法(四分位距法)

不依赖正态分布,鲁棒性更好。用 Q1 和 Q3 算 IQR,然后划定上下界。

def detect_outliers_iqr(data):
    Q1 = np.percentile(data, 25)
    Q3 = np.percentile(data, 75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    outliers = (data < lower) | (data > upper)
    return outliers
注意: 系数1.5是经验值。在失效分析中,如果异常代价很高(比如漏报一个故障会导致停机),我会把系数调小到1.0,宁可多报,不可漏报。

4.2.3 两种方法对比

方法 适用场景 优点 缺点
3σ 正态分布、对称数据 理论成熟、计算快 对偏态敏感、受极端值影响大
IQR 偏态分布、含噪声数据 鲁棒性强、不依赖分布 对尾部数据不敏感

我个人习惯,先用 IQR 做初筛,再用 3σ 做复核。两套方法都标记为异常的,基本可以确定是真正的异常点。

4.3 数据标准化与归一化

不同特征的量纲不一样。比如温度是 0~100℃,压力是 0~10 MPa。如果不做标准化,模型会天然偏向数值大的特征。说白了,就是尺子不一样,没法比。

4.3.1 归一化(Min-Max Scaling)

把数据缩放到 [0, 1] 区间。

def min_max_scaling(data):
    min_val = np.min(data)
    max_val = np.max(data)
    scaled = (data - min_val) / (max_val - min_val)
    return scaled

适合数据有明确上下界的场景,比如图像像素值。但缺点也很明显——对异常值敏感。如果有一个极端大值,其他数据会被压缩到很小。

4.3.2 标准化(Z-score Normalization)

把数据变成均值为0、标准差为1的分布。

def z_score_normalization(data):
    mean = np.mean(data)
    std = np.std(data)
    normalized = (data - mean) / std
    return normalized

适合数据近似正态分布的场景。很多机器学习算法(如SVM、PCA)默认数据是标准化的。我在做振动信号分析时,几乎都用 Z-score,因为它保留了原始数据的分布形状。

4.3.3 怎么选?

场景 推荐方法 原因
数据有界、无异常值 归一化 保持原始比例
数据有异常值、分布未知 标准化 鲁棒性更好
需要保留稀疏性 标准化 归一化会破坏稀疏结构
神经网络输入 归一化 加速收敛
避坑指南: 我曾经犯过一个错——先拆分训练集和测试集,再对整个数据集做标准化。结果测试集的信息泄露到了训练集里,模型评估虚高。正确的做法是:用训练集的均值和标准差去变换测试集。

4.4 时间序列对齐

多源数据采集,时间戳往往不一致。有的传感器采样频率是 100Hz,有的是 10Hz,还有的是事件触发。不对齐,就没法做联合分析。

4.4.1 重采样

把不同频率的数据统一到同一个时间基准上。常用方法:

  • 降采样: 高频数据变低频。用均值、最大值或最小值聚合。比如把 100Hz 的振动数据降成 1Hz,取每秒的 RMS 值。
  • 升采样: 低频数据变高频。用插值或填充。比如把 1Hz 的温度数据升到 10Hz,用线性插值填补中间点。
import pandas as pd

# 假设有两个时间序列
ts1 = pd.Series([1, 2, 3], index=pd.to_datetime(['2024-01-01 10:00:00',
                                                  '2024-01-01 10:00:01',
                                                  '2024-01-01 10:00:02']))
ts2 = pd.Series([10, 20], index=pd.to_datetime(['2024-01-01 10:00:00',
                                                  '2024-01-01 10:00:02']))

# 统一重采样到 1Hz,用前向填充
ts1_resampled = ts1.resample('1S').ffill()
ts2_resampled = ts2.resample('1S').ffill()

4.4.2 时间窗口对齐

不是所有场景都需要精确到毫秒。有时候,用滑动窗口做对齐更实用。比如,把 10 秒内的所有数据点归到一个窗口里,取统计特征(均值、方差、峰值)。

核心思路: 对齐的本质是找到一个共同的时间参考系。要么用固定频率重采样,要么用事件窗口聚合。

4.4.3 对齐中的常见坑

  • 时区问题: 不同设备可能用不同时区。统一转成 UTC。
  • 时钟漂移: 设备长时间运行后,本地时钟会偏差。需要 NTP 同步或事后校正。
  • 丢包导致的时间戳空洞: 重采样后会出现 NaN。我一般用前向填充+插值组合,实在不行就标记为缺失。

4.5 本章知识体系

下面这张图,把数据清洗与预处理的几个核心模块串起来了。你可以把它当成一个检查清单,每次做数据预处理时对照着走一遍。

数据清洗与预处理知识体系 原始数据 缺失值处理 异常值检测 标准化与归一化 时间序列对齐 直接删除 均值/中位数填充 前向/后向填充 插值法 模型预测填充 3σ 法则 IQR 方法 箱线图辅助 领域阈值 Min-Max 归一化 Z-score 标准化 Robust Scaling 重采样 时间窗口聚合 时区校正 时钟漂移补偿 核心原则:先理解数据,再动手清洗 缺失机制、异常含义、对齐基准——每一步都要问自己:为什么?

数据清洗这件事,没有银弹。每个项目的数据都不一样,但方法论是通用的。你只要把缺失、异常、量纲、时间这四个维度理清楚,预处理这关就算过了。