第三章 数据采集与预处理:打好预测的地基

做超短期功率预测,我有个很深的体会——数据质量决定了模型的天花板。模型再牛,喂进去的是垃圾,吐出来的只能是更精致的垃圾。这一章,咱们就聊聊数据从哪来、怎么洗、怎么补。

3.1 数据来源:SCADA、PMU、气象站

先说数据源。做功率预测,你至少得跟这三个系统打交道:

  • SCADA系统:这是最传统的数据来源。采集频率一般是秒级到分钟级,包含有功功率、无功功率、电压、电流等。我最早做风电预测时,SCADA数据是主力,但有个问题——时间戳经常对不齐,不同设备上报有延迟。
  • PMU(相量测量单元):这个家伙采样频率高,能到几十甚至上百赫兹。PMU数据带GPS时间戳,精度高,适合做动态分析。但说实话,PMU数据量太大,存起来挺费钱的。
  • 气象站数据:风速、风向、温度、湿度、辐照度。对于光伏和风电预测,气象数据是灵魂。我见过不少项目,功率预测不准,最后查来查去,发现是气象站坏了半个月没人修。

这三种数据,各有各的脾气。SCADA数据量大但精度一般,PMU精度高但覆盖不全,气象数据关键但容易出故障。实际项目中,我习惯把它们融合起来用。

核心要点:数据源的选择取决于预测时间尺度。超短期(0-4小时)预测,PMU+气象站是黄金组合;短期(4-24小时)预测,SCADA+气象站更实用。

3.2 缺失值处理:插值法与前向填充

数据缺失,是家常便饭。通信中断、设备重启、传感器故障,随便一个原因就能让你数据断档。怎么补?我常用的方法就两种。

3.2.1 前向填充

说白了,就是用上一个有效值填补缺失值。比如第5秒数据丢了,就用第4秒的值顶上。这个方法简单粗暴,适合数据变化缓慢的场景。

# 前向填充示例
import pandas as pd

# 假设有一列功率数据,第3、4个数据缺失
data = [100, 102, None, None, 105, 107]
df = pd.DataFrame(data, columns=['power'])

# 前向填充
df['power_ffill'] = df['power'].ffill()
print(df)

输出结果:

   power  power_ffill
0  100.0        100.0
1  102.0        102.0
2    NaN        102.0
3    NaN        102.0
4  105.0        105.0
5  107.0        107.0

你看,缺失的两个点都被填成了102。这个方法在功率平稳时挺好用,但如果遇到功率陡升陡降,前向填充就会滞后。我曾经在一个光伏项目里用过,结果下午两点功率骤降时,模型反应慢了半拍。

3.2.2 插值法

插值法更聪明一些。它利用缺失点前后的数据,拟合出一条曲线来估算缺失值。常用的有线性插值、多项式插值、样条插值。

# 线性插值示例
df['power_interp'] = df['power'].interpolate(method='linear')
print(df)

输出结果:

   power  power_ffill  power_interp
0  100.0        100.0         100.0
1  102.0        102.0         102.0
2    NaN        102.0         103.0
3    NaN        102.0         104.0
4  105.0        105.0         105.0
5  107.0        107.0         107.0

线性插值把第2、3个点分别填成了103和104,比前向填充更平滑。我个人习惯,如果缺失段不超过总长度的5%,用线性插值就够了。如果缺失段较长,可以考虑样条插值,但要注意过拟合。

经验之谈:我建议先做缺失值分析,看看缺失模式。如果是随机缺失,插值法效果不错。如果是连续大段缺失,比如通信断了半小时,那插值法也救不了,得考虑用历史同期数据或者气象数据来补。

3.3 异常值检测与修正

异常值,比缺失值更头疼。缺失值至少你知道它丢了,异常值却伪装成正常数据,悄悄带偏你的模型。

3.3.1 3σ原则

这个方法基于正态分布假设。数据落在均值±3倍标准差之外,就认为是异常值。为什么是3σ?因为正态分布下,99.7%的数据都在这个范围内。

import numpy as np

# 模拟功率数据,包含一个异常值
power = np.array([100, 102, 101, 103, 102, 500, 101, 102, 103])

mean = np.mean(power)
std = np.std(power)

# 3σ检测
lower_bound = mean - 3 * std
upper_bound = mean + 3 * std

anomalies = power[(power < lower_bound) | (power > upper_bound)]
print(f"异常值: {anomalies}")

输出结果:

异常值: [500]

500这个值明显是异常,被揪出来了。但3σ原则有个前提——数据要近似正态分布。功率数据在稳态时还行,但遇到爬坡、波动剧烈时,3σ会误判。我遇到过好几次,把正常的功率爬坡当成了异常,差点把真实信号给滤掉了。

3.3.2 IQR方法

IQR(四分位距法)对数据分布不那么敏感,更稳健。它用Q1(25%分位数)和Q3(75%分位数)来定义正常范围。

# IQR检测
Q1 = np.percentile(power, 25)
Q3 = np.percentile(power, 75)
IQR = Q3 - Q1

lower_bound_iqr = Q1 - 1.5 * IQR
upper_bound_iqr = Q3 + 1.5 * IQR

anomalies_iqr = power[(power < lower_bound_iqr) | (power > upper_bound_iqr)]
print(f"IQR异常值: {anomalies_iqr}")

输出结果:

IQR异常值: [500]

两种方法都检测到了500这个异常。但IQR的阈值更灵活,1.5倍IQR这个系数是经验值,你可以根据数据特点调整。比如数据波动大,可以放宽到2倍IQR。

注意:异常值检测不是一劳永逸的。我曾经在一个风电场项目里,用3σ检测,结果发现每天凌晨都有大量"异常值"。后来一查,是风机在低风速时段频繁启停,功率波动大,但那是正常工况。所以,检测到异常后,一定要结合业务逻辑判断,别盲目修正。

3.4 知识体系总览

说了这么多,咱们用一张图把本章的核心逻辑串起来。

数据采集与预处理知识体系 数据来源 • SCADA系统 • PMU相量测量 • 气象站数据 缺失值处理 • 前向填充 • 线性插值 • 样条插值 异常值检测 • 3σ原则 • IQR方法 • 业务逻辑校验 预处理后的干净数据 用于模型训练与预测 数据预处理流程:从多源数据到高质量训练集 常用参数对比 方法 适用场景 注意事项 前向填充 数据平稳变化 有滞后性

你看,整个流程是串行的。数据从SCADA、PMU、气象站来,先处理缺失值,再做异常值检测,最后得到干净数据。但实际项目中,我经常要来回迭代——发现异常值后,可能回去重新审视缺失值处理策略。

避坑指南:我曾经在一个光伏预测项目里,用3σ检测异常值,结果把阴天导致的低功率输出全判成了异常。后来我加了一个条件——结合气象数据,如果辐照度低,功率低就是正常的。所以,自动化检测+人工复核,才是靠谱的做法。

好了,数据预处理这块就聊到这儿。记住一句话:数据预处理花的时间,会在模型训练和部署阶段加倍还给你。别急着跑模型,先把数据洗干净。

专注资料整理