特征工程:让气象数据真正“说话”
大家好,我是老张。在风电行业摸爬滚打了十来年,今天咱们聊聊特征工程这个环节。
说实话,很多人觉得模型才是核心。但我个人经验告诉我——特征工程做得好,模型就成功了一半。你想想看,再牛的算法,喂进去的是垃圾数据,吐出来的只能是垃圾预测。
这一章,我带你手把手把原始气象数据,变成模型能“吃”懂的特征。
3.1 气象特征提取:风速、风向、温度、气压
先说最基础的气象特征。这四个变量,是风电预测的“四大金刚”。
| 特征 | 单位 | 说明 | 我的经验 |
|---|---|---|---|
| 风速 | m/s | 核心变量,直接决定发电量 | 注意异常值,比如突然跳变到100m/s |
| 风向 | 度(0-360) | 影响机组对风效率 | 建议拆成sin/cos分量,后面会讲 |
| 温度 | ℃ | 影响空气密度 | 昼夜温差大的地方,这个特征很关键 |
| 气压 | hPa | 同样影响空气密度 | 高原风场要特别关注 |
这里有个坑,我必须要提醒你。
⚠️ 风向的“0度陷阱”
风向是0-360度的循环变量。0度和360度其实是同一个方向。
如果你直接把“风向”这个数值喂给模型,模型会认为0度和360度差了360个单位——这完全错了!
我曾经因为这个疏忽,模型预测偏差大了将近20%。
风向是0-360度的循环变量。0度和360度其实是同一个方向。
如果你直接把“风向”这个数值喂给模型,模型会认为0度和360度差了360个单位——这完全错了!
我曾经因为这个疏忽,模型预测偏差大了将近20%。
怎么解决?很简单,把风向拆成两个分量:
# 风向分解:sin和cos分量
import numpy as np
wind_direction_rad = np.deg2rad(df['wind_direction'])
df['wind_dir_sin'] = np.sin(wind_direction_rad)
df['wind_dir_cos'] = np.cos(wind_direction_rad)
这样一来,模型就能理解“风向”是个圆,而不是一条直线。
3.2 时间特征构造:小时、季节、月份
风电有个特点——时间规律性特别强。你想想看,白天风大还是晚上风大?夏天风多还是冬天风多?
所以,时间特征必须做。我一般会构造这三类:
- 小时特征:0-23,反映日内变化。比如午后风速通常较大。
- 月份特征:1-12,反映季节变化。比如春季风大,夏季风小。
- 季节特征:春/夏/秋/冬,可以编码成0/1/2/3。
但注意,小时和月份也是循环变量。23点和0点只差1小时,但数值上差了23。所以——
💡 我的习惯做法
小时和月份也做sin/cos分解,跟风向一样。
这样模型就能学到“23点之后是0点”这个规律。
小时和月份也做sin/cos分解,跟风向一样。
这样模型就能学到“23点之后是0点”这个规律。
# 时间特征构造
df['hour'] = df['timestamp'].dt.hour
df['month'] = df['timestamp'].dt.month
df['season'] = df['month'].apply(lambda x: (x%12 + 3)//3) # 春0夏1秋2冬3
# 循环变量分解
hour_rad = 2 * np.pi * df['hour'] / 24
month_rad = 2 * np.pi * df['month'] / 12
df['hour_sin'] = np.sin(hour_rad)
df['hour_cos'] = np.cos(hour_rad)
df['month_sin'] = np.sin(month_rad)
df['month_cos'] = np.cos(month_rad)
3.3 滞后特征与滚动窗口特征
这部分是很多新手容易忽略的。说白了,风是有“惯性”的。
什么意思?如果前10分钟风速是10m/s,那接下来5分钟大概率不会突然掉到2m/s。这就是时间序列的“自相关性”。
所以,我们要把过去时刻的信息,作为当前时刻的特征。
滞后特征(Lag Features)
滞后特征,就是取过去某个时刻的值。比如:
- lag_1:前1个时刻的风速
- lag_3:前3个时刻的风速
- lag_6:前6个时刻的风速
我一般会取滞后1、2、3、6、12、24个时刻。为什么?因为近期的变化更重要,远期的参考价值递减。
# 构造滞后特征
for lag in [1, 2, 3, 6, 12, 24]:
df[f'wind_speed_lag_{lag}'] = df['wind_speed'].shift(lag)
⚠️ 注意数据泄露!
构造滞后特征时,一定要用历史数据,不能用未来数据。
我见过有人不小心用了shift(-1),结果模型在测试集上表现“完美”——因为偷看了未来数据。
记住:shift(正数)是取过去,shift(负数)是取未来。
构造滞后特征时,一定要用历史数据,不能用未来数据。
我见过有人不小心用了shift(-1),结果模型在测试集上表现“完美”——因为偷看了未来数据。
记住:shift(正数)是取过去,shift(负数)是取未来。
滚动窗口特征(Rolling Window Features)
滞后特征只取一个点,但滚动窗口特征取的是一个时间段。比如:
- 过去1小时的平均风速
- 过去3小时的风速标准差
- 过去6小时的最大风速
这些统计量,能反映风速的“趋势”和“波动性”。
# 构造滚动窗口特征
window_sizes = [3, 6, 12] # 窗口大小,单位是时间步
for w in window_sizes:
df[f'wind_speed_rolling_mean_{w}'] = df['wind_speed'].rolling(window=w).mean()
df[f'wind_speed_rolling_std_{w}'] = df['wind_speed'].rolling(window=w).std()
df[f'wind_speed_rolling_max_{w}'] = df['wind_speed'].rolling(window=w).max()
df[f'wind_speed_rolling_min_{w}'] = df['wind_speed'].rolling(window=w).min()
嗯,这里要注意:滚动窗口会引入NaN值。因为前几个时刻没有足够的历史数据。我一般会直接删除这些行,或者用前向填充。
3.4 本章知识体系总览
说了这么多,我画了一张图帮你理清思路。特征工程的核心逻辑,其实就是三步:
📌 核心要点回顾
- 气象特征:风速、风向(拆sin/cos)、温度、气压
- 时间特征:小时、月份、季节,同样做循环分解
- 滞后特征:取过去N个时刻的值,反映短期惯性
- 滚动窗口特征:取一段时间的统计量,反映趋势和波动
记住:特征工程没有标准答案。不同风场、不同季节、不同机型,最优特征组合都不一样。多试、多调、多验证,才是王道。
公众号:蓝海资料掘金营,微信deep3321