3、数据质量评估:数据完整性检查、异常值检测(3σ原则、IQR方法)、缺失值模式分析、时间戳对齐问题

各位工程师朋友,咱们接着聊。上一章我们把数据从历史库里捞了出来,但说实话,捞出来的数据能不能直接用?我个人的经验是——千万别信。SCADA系统的数据,说白了就是现场传感器、PLC、RTU一层层传上来的,中间经过了多少噪声干扰、通信丢包、设备故障,你根本想象不到。

我记得有一次,一个水处理项目,现场报上来一个液位数据,连续三天都是0.00。操作员以为是水池空了,差点启动紧急补水。我一看,嗯,传感器线被老鼠咬断了。所以,数据质量评估是数据挖掘的第一步,也是最重要的一步。你想想看,垃圾数据进去,再牛的算法也白搭。

这一章,我们就来拆解数据质量评估的四个核心维度:完整性检查、异常值检测、缺失值模式分析、时间戳对齐。我会把我在项目中踩过的坑、总结的经验,都揉碎了讲给你听。

数据质量评估 完整性检查 字段空值率、记录缺失 异常值检测 3σ原则、IQR方法 缺失值模式分析 MCAR/MAR/MNAR 时间戳对齐 抖动、漂移、时区 输出:高质量清洗数据集

3.1 数据完整性检查

完整性检查,说白了就是看看数据有没有缺胳膊少腿。我习惯从两个维度入手:字段级完整性记录级完整性

字段级完整性,就是看每个字段有多少空值。比如一个温度测点,理论上应该每分钟一条数据,结果发现某一天有30%的时间戳是空的。嗯,这就有问题了。

我一般会先算一个空值率

# 计算每个字段的空值率
import pandas as pd

def check_null_ratio(df):
    null_ratio = df.isnull().sum() / len(df) * 100
    return null_ratio.sort_values(ascending=False)

# 举个例子
null_info = check_null_ratio(scada_data)
print(null_info[null_info > 0])  # 只看有空值的字段

记录级完整性,则是看时间序列有没有断点。比如你期望每5分钟一条数据,结果从下午2点到3点之间一条都没有。这可能是通信中断,也可能是PLC死机了。

我的经验阈值:

  • 空值率 < 1%:数据质量优秀,可以直接用
  • 空值率 1% ~ 5%:需要关注,但通常可以插补
  • 空值率 > 5%:必须排查原因,不能直接使用

小技巧:我习惯把空值率做成热力图,一眼就能看出哪些测点、哪些时间段问题最严重。颜色越深,问题越大。

3.2 异常值检测:3σ原则与IQR方法

异常值检测,这是数据质量评估的重头戏。SCADA数据里的异常值,说白了就是那些「离谱」的数据点。比如一个压力变送器,正常范围是0~10MPa,结果突然蹦出来一个100MPa。这要么是传感器坏了,要么是通信受到了干扰。

我常用的方法有两种:3σ原则IQR方法。它们各有各的适用场景。

3σ原则

3σ原则基于正态分布假设。简单说,就是数据落在均值±3个标准差之外的概率只有0.3%。如果某个数据点落在这个范围之外,我就认为它是异常值。

def detect_outliers_3sigma(data_series):
    mean = data_series.mean()
    std = data_series.std()
    lower_bound = mean - 3 * std
    upper_bound = mean + 3 * std
    outliers = data_series[(data_series < lower_bound) | (data_series > upper_bound)]
    return outliers, lower_bound, upper_bound

# 举个例子
outliers, low, high = detect_outliers_3sigma(pressure_data)
print(f"检测到 {len(outliers)} 个异常值,范围: [{low:.2f}, {high:.2f}]")

注意:3σ原则对异常值本身很敏感。如果数据里已经有很多异常值,均值和标准差会被「带偏」,导致检测失效。我曾经在一个流量计数据上吃过这个亏——数据里有一堆尖峰,结果3σ把正常值也判成了异常。

IQR方法

IQR方法,也就是四分位距法,它不依赖正态分布假设,对异常值的鲁棒性更好。它的逻辑是:计算数据的Q1(25%分位数)和Q3(75%分位数),然后定义IQR = Q3 - Q1。通常认为,小于Q1 - 1.5×IQR或大于Q3 + 1.5×IQR的数据是异常值。

def detect_outliers_iqr(data_series):
    Q1 = data_series.quantile(0.25)
    Q3 = data_series.quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    outliers = data_series[(data_series < lower_bound) | (data_series > upper_bound)]
    return outliers, lower_bound, upper_bound

# 举个例子
outliers_iqr, low_iqr, high_iqr = detect_outliers_iqr(pressure_data)
print(f"IQR方法检测到 {len(outliers_iqr)} 个异常值")

我的选择建议:

  • 数据近似正态分布(比如温度、液位)→ 用3σ原则
  • 数据分布偏斜严重(比如流量、压力尖峰)→ 用IQR方法
  • 实在拿不准 → 两个都跑一遍,取交集或并集

3.3 缺失值模式分析

很多人一看到缺失值,就直接用均值填充或者前向填充。我告诉你,千万别这么干。缺失值不是凭空出现的,它背后往往有原因。你需要先搞清楚缺失值的模式

统计学上把缺失值分为三种模式:

模式 含义 SCADA场景举例 处理建议
MCAR
完全随机缺失
缺失与否与数据本身无关 通信偶尔丢包,随机缺失 可以直接删除或简单插补
MAR
随机缺失
缺失与否与其他变量有关 温度过高时,传感器保护性停机导致数据缺失 需要用其他变量建模预测
MNAR
非随机缺失
缺失与否与缺失值本身有关 液位超过量程时,传感器输出满量程值(实际已失效) 必须排查物理原因,不能简单插补

我习惯用缺失值热力图缺失值关联分析来判断模式。比如,我发现A测点缺失的时候,B测点也经常缺失,那可能就是共因故障(比如同一个通信模块坏了)。

# 缺失值关联分析示例
def missing_correlation(df):
    # 将数据转为是否缺失的布尔矩阵
    missing_matrix = df.isnull().astype(int)
    # 计算缺失模式之间的相关系数
    corr = missing_matrix.corr()
    return corr

# 如果两个测点的缺失相关系数 > 0.8,说明它们很可能共享同一个故障源

避坑指南:我曾经在一个风电项目里,发现所有风速大于25m/s时的数据都缺失了。一开始以为是随机缺失,后来才发现是风速计在强风下被吹坏了。这就是典型的MNAR——缺失值本身就和风速有关。如果当时用均值填充,那后续的发电量预测模型就全废了。

3.4 时间戳对齐问题

时间戳对齐,这是SCADA数据挖掘里最容易被忽视、但也是最坑人的问题。你想想看,一个工厂里可能有几十个PLC,每个PLC的时钟可能都不一样。有的快几秒,有的慢几分钟。如果不做对齐,你分析出来的结果就是「鸡同鸭讲」。

我遇到过最离谱的一次,是一个化工项目,DCS系统和PLC系统的时间差了整整8分钟。结果我做的物料平衡计算,怎么算都对不上。后来发现,DCS用的是北京时间,PLC用的是UTC时间,差了8小时。嗯,这锅得让工程师背。

时间戳对齐主要解决三个问题:

  • 时间抖动(Jitter):数据到达时间不稳定,比如本该整点到的数据,有时候早2秒,有时候晚3秒
  • 时间漂移(Drift):时钟逐渐偏离标准时间,比如一天慢1秒
  • 时区/夏令时问题:不同系统使用不同时区,或者夏令时切换导致数据重复/缺失

我的对齐策略是这样的:

def align_timestamps(df, freq='5T', method='ffill'):
    """
    时间戳对齐函数
    freq: 目标频率,如'5T'表示5分钟
    method: 填充方法,'ffill'前向填充,'bfill'后向填充,'interpolate'插值
    """
    # 1. 确保时间戳是datetime类型
    df.index = pd.to_datetime(df.index)
    
    # 2. 创建标准时间轴
    start = df.index.min().ceil(freq)
    end = df.index.max().floor(freq)
    standard_index = pd.date_range(start=start, end=end, freq=freq)
    
    # 3. 重新索引并对齐
    df_aligned = df.reindex(standard_index)
    
    # 4. 填充缺失值
    if method == 'ffill':
        df_aligned = df_aligned.fillna(method='ffill')
    elif method == 'interpolate':
        df_aligned = df_aligned.interpolate()
    
    return df_aligned

# 使用示例
aligned_data = align_timestamps(raw_data, freq='1T', method='interpolate')

特别提醒:时间戳对齐时,一定要保留原始时间戳作为备用。我见过有人直接覆盖了原始数据,结果发现对齐逻辑有bug,想回退都回退不了。我的习惯是,在数据框里加一列 original_timestamp,永远不删。

小结

数据质量评估,说白了就是给数据「体检」。完整性检查看有没有缺胳膊少腿,异常值检测看有没有离谱的数据点,缺失值模式分析看缺失背后的原因,时间戳对齐确保所有数据在同一个时间轴上说话。

这四步走完,你的数据才算真正「能用」。下一阶段,我们就可以开始做特征工程了。但那是后话,先把眼前的数据质量搞扎实。

记住一句话:数据质量决定了分析的天花板。算法再牛,也救不了烂数据。


公众号:蓝海资料掘金营,微信deep3321