3、数据预处理基础:数据清洗、重采样与标准化

各位同学,今天我们来聊聊数据预处理。说实话,这是整个风电功率预测里最枯燥、但也是最要命的一环。我见过太多模型跑出来效果奇差,最后查来查去,问题都出在数据上。数据没洗干净,后面再牛的算法也是白搭。

3.1 数据清洗:把脏东西筛出去

风电数据有多脏?我跟你讲,我入行第一年接手一个风场的历史数据,打开一看,好家伙,风速负值、功率超额定值、时间戳乱跳……当时我就懵了。后来我养成了一个习惯:拿到数据第一件事,不是建模,而是先做数据质量分析。

3.1.1 异常值处理

异常值说白了就是那些明显不合理的数据点。比如风速不可能超过切出风速,功率不可能为负,这些一眼就能看出来。

常用的检测方法:

  • 3σ原则:数据服从正态分布时,超出均值±3倍标准差的值视为异常。我个人习惯先用这个方法快速扫一遍。
  • 箱线图法:用四分位距(IQR)来判定。超出Q1-1.5×IQR或Q3+1.5×IQR的点,基本就是异常。
  • 业务规则法:这个最靠谱。比如风速0~25m/s,功率0~额定功率,这些边界条件你得心里有数。

避坑指南:我曾经遇到过一个风场,连续三天风速都是15.0m/s,纹丝不动。用3σ检测没发现问题,但一看就知道是传感器卡死了。所以啊,业务规则和统计方法要结合着用。

处理方式:

  • 直接删除:异常点不多时,删了最省事。但别删太多,否则样本量不够。
  • 替换为阈值:比如风速超过25m/s,直接替换成25m/s。嗯,这个做法有点粗暴,但有时候管用。
  • 插值填补:用前后正常值做线性插值,或者用邻近点的均值。
# 一个简单的异常值检测示例
import pandas as pd
import numpy as np

def detect_outliers_iqr(data, column):
    Q1 = data[column].quantile(0.25)
    Q3 = data[column].quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    outliers = data[(data[column] < lower) | (data[column] > upper)]
    return outliers

# 我一般会先打印异常值数量,再决定怎么处理
outliers = detect_outliers_iqr(df, 'wind_speed')
print(f'发现 {len(outliers)} 个异常风速点')

3.1.2 缺失值处理

缺失值在风电数据里太常见了。通讯中断、传感器故障、维护停机……都会导致数据缺失。你想想看,一个风场几十台风机,每天产生海量数据,出现缺失是必然的。

缺失值类型:

  • 完全随机缺失:比如某台风机突然断网了10分钟。这种最好处理。
  • 随机缺失:比如风速越大,传感器越容易出故障。这种有点麻烦。
  • 非随机缺失:比如功率超过某个阈值时,数据就丢了。这种最头疼,处理不好会引入偏差。

我的处理策略:

  • 连续缺失不超过3个点:用线性插值。简单、快速、效果还行。
  • 连续缺失3~10个点:用前后24小时同一时刻的数据做均值填充。风电有日周期性,这个办法挺实用。
  • 连续缺失超过10个点:我建议直接删掉这段数据。强行填充反而会引入噪声。

小技巧:填充缺失值后,一定要检查填充效果。我习惯画个折线图,看看填充点附近有没有突兀的跳变。如果有,说明填充方法不合适。

# 缺失值处理示例
# 线性插值
df['wind_speed'] = df['wind_speed'].interpolate(method='linear')

# 用前后24小时同一时刻均值填充
df['power'] = df['power'].fillna(
    df.groupby(df.index.hour)['power'].transform('mean')
)

3.2 时间序列重采样

风电数据采集频率五花八门。有的风场是1秒一个点,有的是10分钟一个点,还有的是1小时一个点。做预测时,你得把它们统一到同一个时间尺度上。这就是重采样。

为什么需要重采样?

  • 不同来源的数据频率不一致,没法直接建模
  • 高频数据噪声大,降采样可以平滑信号
  • 低频数据信息量不够,升采样可以对齐时间轴

重采样方法:

  • 降采样(高频→低频):比如10分钟数据降为1小时。常用聚合函数:均值、中位数、最大值。我个人习惯用均值,但如果是做极端风况分析,用最大值更合适。
  • 升采样(低频→高频):比如1小时数据升为15分钟。常用方法:前向填充、线性插值、三次样条插值。注意,升采样不会增加信息量,只是让数据看起来更密。

注意:升采样时千万别用后向填充!我曾经犯过这个错,用后向填充把未来的信息泄露到了过去,模型在测试集上表现好得离谱,一上线就崩了。这种错误很隐蔽,大家一定要小心。

# 重采样示例
# 将10分钟数据降采样为1小时,取均值
df_hourly = df.resample('1H').mean()

# 将1小时数据升采样为15分钟,线性插值
df_15min = df_hourly.resample('15T').interpolate(method='linear')

3.3 数据标准化与归一化

标准化和归一化,这两个概念经常被搞混。我简单说一下:

  • 归一化(Min-Max Scaling):把数据缩放到[0,1]区间。公式:(x - min) / (max - min)
  • 标准化(Z-score Scaling):把数据变成均值为0、标准差为1的分布。公式:(x - mean) / std

什么时候用哪个?

  • 如果你的数据分布比较均匀,没有太多异常值,归一化就够了
  • 如果数据有异常值,或者分布是长尾的,标准化更稳健
  • 对于深度学习模型(比如LSTM),我习惯用标准化。因为归一化对异常值太敏感了。

我的经验:标准化后的数据,模型收敛速度明显更快。尤其是做风电功率预测时,风速和功率的量级差很多(风速0~25,功率0~1500),不标准化的话,模型会把大部分注意力放在功率上,风速的信息就学不到了。

from sklearn.preprocessing import StandardScaler, MinMaxScaler

# 标准化
scaler_std = StandardScaler()
df_scaled = scaler_std.fit_transform(df[['wind_speed', 'power']])

# 归一化
scaler_mm = MinMaxScaler()
df_normalized = scaler_mm.fit_transform(df[['wind_speed', 'power']])

3.4 本章知识体系

下面这张图是我自己整理的,把数据预处理的流程串起来了。你跟着这个流程走,基本不会出大问题。

数据预处理流程 原始数据 数据清洗 异常值检测与处理 缺失值填充 重复值去重 时间序列重采样 降采样(高频→低频) 升采样(低频→高频) 标准化 / 归一化

这张图把整个流程串起来了:原始数据先进数据清洗,把脏东西去掉;然后做重采样,统一时间尺度;最后做标准化或归一化,让数据适合模型输入。每一步都有坑,但按这个流程走,至少不会出大问题。

最后说一句:数据预处理没有标准答案。不同的风场、不同的数据质量、不同的预测目标,处理方式都不一样。我的建议是:多试几种方法,看看哪种效果最好。别怕麻烦,这一步省下的时间,后面建模时会加倍还给你。

专注资料整理