3、SCADA数据质量:数据缺失、异常值、噪声处理、数据清洗实战
各位同学,咱们今天聊点实在的。
SCADA系统采集回来的数据,说白了就是风机的「体检报告」。但这份报告,经常缺斤少两,甚至满嘴跑火车。我见过太多项目,模型建得漂漂亮亮,一上真实数据就崩了——问题全出在数据质量上。
所以,这一章咱们就动手,把那些脏数据、坏数据、假数据,一个一个揪出来处理掉。
3.1 数据缺失:不是所有「空」都是坏事
SCADA数据缺失,太常见了。传感器掉线、通讯中断、存储故障,随便一个原因就能让你某段时间的数据变成一片空白。
我个人习惯,拿到数据第一件事,先看缺失率。
核心原则:缺失率低于5%,可以补;5%-20%,看情况;超过20%,直接弃用该通道。
补缺失的方法,我按场景分三类:
- 线性插值:适用于短时间缺失(比如连续缺失3个点以内)。简单说,就是拿前后两个点的平均值填进去。我在项目中处理风速数据时常用,效果不错。
- 前向填充:适用于状态量,比如「风机运行/停机」这种开关量。缺失了?就用上一个状态。你想想看,风机不会无缘无故在1秒内从运行变成停机,对吧?
- 模型预测填充:适用于长时间缺失。用其他相关通道(比如有功功率、桨距角)去预测缺失的风速。这招我曾在某海上风电场用过,效果比插值好很多。
# 线性插值示例
import pandas as pd
df['风速'].interpolate(method='linear', inplace=True)
# 前向填充
df['状态'].fillna(method='ffill', inplace=True)
小技巧:补完缺失后,一定要做一次「合理性校验」。我曾经补完数据没检查,结果发现某台风机的风速连续3小时都是5.0m/s——一看就是插值插出来的假数据。
3.2 异常值:那些「离谱」的数据点
异常值,说白了就是数据里的「刺头」。风速突然飙到50m/s?功率变成负数?这些明显不符合物理规律的数据,必须处理。
我常用的方法有三种:
- 3σ原则:适用于正态分布的数据。超出均值±3倍标准差的数据,视为异常。简单粗暴,但有效。
- IQR方法:适用于非正态分布。用四分位距(Q3-Q1)来界定异常范围。我个人更推荐这个方法,因为SCADA数据大多不是正态分布。
- 物理约束:这是最靠谱的。比如风速不能超过切出风速(通常25m/s),功率不能超过额定功率的1.2倍。这些规则,直接写死在代码里。
# IQR方法示例
Q1 = df['风速'].quantile(0.25)
Q3 = df['风速'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df = df[(df['风速'] >= lower_bound) & (df['风速'] <= upper_bound)]
注意:不要一刀切!异常值有时是真实事件。比如风机在极端天气下的超速运行,虽然数据「异常」,但恰恰是故障分析的关键。我曾经因为误删了这些数据,导致一个故障模型训练失败,后来花了整整一周才找到原因。
3.3 噪声处理:别让「毛刺」干扰你的判断
SCADA数据里的噪声,就像照片上的噪点。单个看没什么,但累积起来,足以让你的模型学偏。
噪声主要来自传感器精度、电磁干扰、振动等。处理噪声,我推荐两种方法:
- 移动平均:最简单,也最常用。取前后N个点的平均值,平滑掉高频噪声。N值一般取3-5,太大就会丢失真实变化趋势。
- 中值滤波:对脉冲噪声(突然的尖峰)效果特别好。我处理振动数据时,几乎必用中值滤波。
# 移动平均
df['风速_平滑'] = df['风速'].rolling(window=5).mean()
# 中值滤波
from scipy.signal import medfilt
df['振动_平滑'] = medfilt(df['振动'], kernel_size=5)
经验之谈:平滑窗口大小,我建议根据采样频率来定。10秒采一次的数据,窗口取3-5;1秒采一次的,窗口可以取10-15。别问我怎么知道的——都是踩坑踩出来的。
3.4 数据清洗实战:一条完整的流水线
好了,理论讲完了。咱们来点实战的。下面是我在项目中常用的一条数据清洗流水线:
def clean_scada_data(df):
# 1. 删除全空行
df.dropna(how='all', inplace=True)
# 2. 缺失值处理(风速、功率等关键通道)
df['风速'].interpolate(method='linear', inplace=True)
df['有功功率'].interpolate(method='linear', inplace=True)
# 3. 异常值处理(物理约束)
df = df[(df['风速'] >= 0) & (df['风速'] <= 25)]
df = df[(df['有功功率'] >= 0) & (df['有功功率'] <= 1.2 * 额定功率)]
# 4. 噪声平滑
df['风速'] = df['风速'].rolling(window=3).mean()
# 5. 去重
df.drop_duplicates(subset=['时间戳'], keep='first', inplace=True)
return df
这条流水线,我用了不下20个项目。每次根据具体数据特点微调一下参数,基本都能搞定。
记住:数据清洗不是一次性工作。每次清洗完,都要做一次可视化检查。把清洗前后的数据画出来对比,一眼就能看出问题。
3.5 知识体系图:数据清洗的核心逻辑
下面这张图,是我自己总结的数据清洗流程。你把它打印出来贴在工位上,每次做清洗前看一眼,保证不迷路。
嗯,这张图的核心逻辑就是:先处理缺失,再干掉异常,最后平滑噪声。每一步做完,都回头看一眼可视化结果。别偷懒,这一步省不了。
最后说一句:数据清洗没有标准答案。每个风场、每台风机、甚至每个季节的数据特点都不一样。我的建议是:先跑一遍通用流程,再根据实际情况微调。做得多了,你自然就有感觉了。
公众号:蓝海资料掘金营,微信deep3321