第1章:数据清洗基础——缺失值填充策略、异常值剔除与重复数据删除
大家好,我是老蓝。在风场干了这么多年数据,我最大的体会就是:SCADA数据从来不会干干净净地等你来用。今天咱们就聊聊数据清洗最基础、也最绕不开的三个活儿——缺失值、异常值和重复数据。
说实话,我刚入行那会儿,拿到风场数据就直接建模,结果模型跑出来一塌糊涂。后来才发现,数据里全是坑。你想想看,传感器偶尔掉线、通讯中断、风机维护停机……这些都会在数据里留下“脏东西”。不清理干净,后面的特征工程全是白搭。
1.1 缺失值填充策略
缺失值,说白了就是数据表里那些空着的格子。我见过最夸张的项目,某个测风塔的数据缺失率高达40%。那怎么办?直接扔掉?太浪费了。咱们得想办法填上。
我个人习惯把缺失值填充分成四类,每类都有它的适用场景:
| 填充方法 | 适用场景 | 我的经验 |
|---|---|---|
| 均值填充 | 数据分布较对称,无明显异常值 | 风速、温度这类指标可以用 |
| 中位数填充 | 数据有偏态分布,或存在异常值 | 功率数据我常用中位数,因为偶尔有极端值 |
| 前向填充 | 时间序列数据,短时间缺失 | SCADA的连续采集数据,缺几分钟很正常 |
| 插值法 | 数据变化平滑,缺失段不长 | 线性插值最常用,但别用在突变点 |
1.1.1 均值与中位数填充
这两种方法最简单,但千万别无脑用。我在项目中遇到过这样的情况:某台风机在强风时段传感器故障,导致风速数据大面积缺失。如果用均值填充,会把强风时段的数据拉低,后续算发电量就会偏小。
正确的做法是:先分组,再填充。比如按季节、按工况分组,每组分别算均值或中位数。
# 按季节分组填充均值
import pandas as pd
df['season'] = df['timestamp'].dt.month.map(lambda x: (x%12+3)//3)
df['wind_speed_filled'] = df.groupby('season')['wind_speed'].transform(
lambda x: x.fillna(x.mean())
)
1.1.2 前向填充
前向填充,就是拿上一个时刻的值来填当前的空缺。这个方法在SCADA数据里特别实用。为什么?因为风场数据是连续采集的,通常每10分钟一条记录。如果某条记录缺失了,大概率是通讯瞬间中断,前后时刻的值变化不大。
我曾经处理过一个项目,某台风机连续3小时数据缺失。用前向填充显然不行——3小时的风况可能完全变了。这时候我会限制填充的最大步长,比如最多往前填充6个点(1小时)。
# 限制前向填充的最大步长
df['wind_speed_ffill'] = df['wind_speed'].fillna(method='ffill', limit=6)
1.1.3 插值法
插值法,说白了就是根据已知数据点,拟合出一条曲线,然后估算缺失点的值。线性插值是最常用的,但如果你面对的是风速这种波动较大的数据,可以考虑用样条插值。
嗯,这里要注意:插值法只适合缺失段较短的情况。如果缺失段太长,插值出来的结果基本就是瞎猜。
# 线性插值
df['wind_speed_interp'] = df['wind_speed'].interpolate(method='linear')
# 时间序列插值(考虑时间间隔)
df['wind_speed_interp'] = df['wind_speed'].interpolate(method='time')
1.2 异常值剔除与修正
异常值,就是那些明显不合理的数据点。比如风速突然飙到100m/s,或者功率为负值。这些数据要么是传感器故障,要么是通讯错误,必须处理掉。
我常用的方法有三种:
- 3σ原则:超出均值±3倍标准差的数据视为异常。适合正态分布的数据。
- IQR方法:超出Q1-1.5IQR或Q3+1.5IQR的数据视为异常。适合偏态分布。
- 业务规则:根据物理常识设定阈值。比如风速不可能超过切出风速太多。
我个人最推荐的是业务规则+IQR的组合。为什么?因为纯统计方法可能会把真实的高风速数据误判为异常。我在一个海上风场项目里就遇到过,台风天风速确实很高,但3σ方法把它当异常剔除了,结果模型低估了极端工况下的发电能力。
# IQR方法剔除异常值
Q1 = df['wind_speed'].quantile(0.25)
Q3 = df['wind_speed'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df_clean = df[(df['wind_speed'] >= lower_bound) & (df['wind_speed'] <= upper_bound)]
1.3 重复数据删除
重复数据,就是完全一样或者几乎一样的记录。SCADA系统偶尔会重复发送数据,或者数据入库时出现重复。重复数据会导致统计结果偏倚,比如算平均风速时,重复的那条会被多算一次。
我一般分两步走:
- 完全重复:所有列都一样的记录,直接删除。
- 近似重复:时间戳相近、数值也相近的记录,需要人工判断。
# 删除完全重复的记录
df = df.drop_duplicates()
# 按指定列判断重复(比如时间戳)
df = df.drop_duplicates(subset=['timestamp'], keep='first')
1.4 本章知识体系
下面这张图是我自己总结的数据清洗流程,你可以把它当作操作手册来用:
这张图看起来简单,但每一步都有很多细节。我建议你在实际项目中,按照这个顺序走一遍。别跳步,也别偷懒。数据清洗虽然枯燥,但它是整个数据分析流程的基石。
好了,这一章的内容就到这里。数据清洗是个手艺活,多练才能找到感觉。下一章咱们聊聊特征工程里的时间特征提取,到时候见。
公众号:蓝海资料掘金营,微信deep3321