第三章 时间序列数据处理:光伏/负荷数据的获取、清洗、归一化与特征工程
各位同学,欢迎来到第三章。前两章我们聊了储能调度的整体架构和算法选型,算是把“地图”和“武器”都认了一遍。从这章开始,咱们要真正动手了。
做调度算法,最怕什么?不是算法不够先进,而是数据一塌糊涂。我见过太多项目,算法模型调得漂漂亮亮,一上真实数据就崩盘。为什么?因为数据管道没建好。说白了,数据是算法的“粮食”,粮食有问题,再好的厨子也白搭。
这一章,我们就来搭建这条数据管道。从数据获取开始,到清洗、归一化,再到特征工程,一步步把原始数据变成算法能吃的“营养餐”。
3.1 数据获取:从哪里来?
光伏和负荷数据,来源其实挺多的。我个人习惯把它们分成三类:
- 实测数据:从电站的SCADA系统、智能电表、逆变器直接采集。这是最真实的数据,但往往有缺失、有噪声。
- 公开数据集:比如NREL的PVDAQ、澳大利亚的Ausgrid数据集。适合做研究、做原型验证。
- 模拟数据:用PVsyst、HOMER等工具生成。适合做极端场景测试,但别太当真。
我在项目中遇到过最头疼的情况:客户给的数据是Excel手动记录的,时间戳格式五花八门,有的带时区,有的不带,有的甚至写的是“上午10点”。嗯,这种数据,清洗起来比写算法还累。
3.2 数据清洗:把垃圾倒掉
数据拿到手,别急着分析。先看看有没有“脏数据”。常见的脏数据有这几类:
| 问题类型 | 典型表现 | 处理方法 |
|---|---|---|
| 缺失值 | 某段时间数据为空 | 插值、前向填充、删除 |
| 异常值 | 光伏功率突然飙到200% | 3σ原则、IQR方法 |
| 重复值 | 同一时间戳出现多条记录 | 去重,保留最新或均值 |
| 时间戳错乱 | 时间顺序颠倒、跳跃 | 排序、重采样 |
举个例子,光伏数据在夜间应该是0,但有时候传感器会飘出几瓦的噪声。这种要不要处理?看情况。如果你做的是日发电量统计,那点噪声无所谓。但如果你做的是秒级调度,那必须滤掉。
下面是一段简单的清洗代码,用Python的pandas库实现:
import pandas as pd
import numpy as np
# 读取数据
df = pd.read_csv('pv_data.csv', parse_dates=['timestamp'])
df.set_index('timestamp', inplace=True)
# 1. 去重
df = df[~df.index.duplicated(keep='first')]
# 2. 排序
df.sort_index(inplace=True)
# 3. 处理缺失值(线性插值)
df['power_kw'] = df['power_kw'].interpolate(method='linear')
# 4. 处理异常值(3σ原则)
mean = df['power_kw'].mean()
std = df['power_kw'].std()
df = df[(df['power_kw'] >= mean - 3*std) & (df['power_kw'] <= mean + 3*std)]
# 5. 重采样到15分钟间隔
df_resampled = df.resample('15T').mean()
3.3 归一化:让数据“公平”竞争
归一化,说白了就是把不同量纲的数据拉到同一个尺度上。光伏功率可能是0-1000kW,负荷可能是0-500kW,温度可能是-10到40度。如果不归一化,算法会天然偏向数值大的特征。
常用的归一化方法有两种:
- Min-Max归一化:把数据缩放到[0,1]区间。公式是 (x - min) / (max - min)。适合数据分布比较均匀的情况。
- Z-score标准化:把数据变成均值为0、标准差为1的分布。公式是 (x - mean) / std。适合数据有异常值的情况。
我个人习惯:对于光伏和负荷数据,优先用Min-Max。因为调度算法往往需要输出具体的功率值,Min-Max方便反归一化。但如果你发现数据里有明显的尖峰,那就用Z-score。
from sklearn.preprocessing import MinMaxScaler
# 假设df已经清洗完毕,包含'pv_power'和'load_power'两列
scaler = MinMaxScaler()
df[['pv_power', 'load_power']] = scaler.fit_transform(df[['pv_power', 'load_power']])
# 保存scaler,后续反归一化用
import joblib
joblib.dump(scaler, 'scaler.pkl')
3.4 特征工程:从数据中“挖”出信息
特征工程,是数据管道里最考验经验的一步。你想想看,原始数据只有功率值和时间戳,但调度算法需要知道“现在是白天还是晚上”、“今天是工作日还是周末”、“未来两小时会不会下雨”。这些信息,都得靠特征工程来提取。
我常用的特征可以分为三类:
3.4.1 时间特征
- 小时、星期几、月份、季节
- 是否工作日、是否节假日
- 距离日出/日落的时间(对光伏特别重要)
3.4.2 统计特征
- 过去1小时、6小时、24小时的滑动均值
- 过去1小时的方差(反映波动性)
- 当前值与历史同期值的差异
3.4.3 外部特征
- 天气预报数据(温度、辐照度、云量)
- 电价信号(如果做的是经济调度)
- 设备状态(逆变器是否在线、电池SOC)
举个例子,光伏功率的预测,光看历史功率是不够的。你加上“当前时刻的理论辐照度”这个特征,预测精度能提升一大截。这个理论辐照度可以用天文算法算出来,不需要传感器。
# 生成时间特征示例
df['hour'] = df.index.hour
df['day_of_week'] = df.index.dayofweek
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
df['month'] = df.index.month
# 滑动统计特征
df['pv_rolling_mean_1h'] = df['pv_power'].rolling(window=4).mean() # 15分钟粒度,4个点=1小时
df['pv_rolling_std_1h'] = df['pv_power'].rolling(window=4).std()
# 理论辐照度(简化版,实际需要经纬度和时间)
# 这里假设一个简单的正弦曲线模拟
import numpy as np
df['solar_angle'] = np.sin(2 * np.pi * (df['hour'] - 6) / 24)
df['solar_angle'] = df['solar_angle'].clip(0) # 夜间为0
3.5 数据管道:把一切串起来
好了,数据获取、清洗、归一化、特征工程都讲完了。但实际项目中,这些步骤不是一次性的。你需要一个自动化的数据管道,每天定时跑,把新数据灌进来,产出特征,喂给模型。
下面这张图,是我常用的数据管道架构:
这张图里,数据从源端进来,经过清洗、归一化、特征工程,存入数据库。调度算法从数据库里读特征,做出决策。决策结果反馈回来,用于优化特征工程和模型参数。这是一个闭环。
3.6 本章小结
这一章我们走完了数据管道的全流程。从数据获取的三种来源,到清洗的五大步骤,再到归一化的两种方法,最后是特征工程的三大类别。每一步都有坑,每一步也都有技巧。
记住一句话:数据管道的质量,决定了算法效果的上限。模型再先进,也救不了垃圾数据。所以,花时间把数据管道搭扎实,绝对是值得的。
下一章,我们会把这些处理好的数据,真正喂进调度算法里。到时候你就知道,前面这些功夫,一点都不会白费。