特征工程:让气象数据真正“说话”

大家好,我是老张。在风电行业摸爬滚打了十来年,今天咱们聊聊特征工程这个环节。

说实话,很多人觉得模型才是核心。但我个人经验告诉我——特征工程做得好,模型就成功了一半。你想想看,再牛的算法,喂进去的是垃圾数据,吐出来的只能是垃圾预测。

这一章,我带你手把手把原始气象数据,变成模型能“吃”懂的特征。

3.1 气象特征提取:风速、风向、温度、气压

先说最基础的气象特征。这四个变量,是风电预测的“四大金刚”。

特征 单位 说明 我的经验
风速 m/s 核心变量,直接决定发电量 注意异常值,比如突然跳变到100m/s
风向 度(0-360) 影响机组对风效率 建议拆成sin/cos分量,后面会讲
温度 影响空气密度 昼夜温差大的地方,这个特征很关键
气压 hPa 同样影响空气密度 高原风场要特别关注

这里有个坑,我必须要提醒你。

⚠️ 风向的“0度陷阱”
风向是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点”这个规律。
# 时间特征构造
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(负数)是取未来。

滚动窗口特征(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) 温度、气压 小时、月份、季节 循环变量sin/cos分解 滞后1/2/3/6/12/24 滚动均值/标准差/最大最小 完整特征集 → 输入模型 特征工程不是越多越好,而是越“对”越好 —— 每个特征都要有物理意义
📌 核心要点回顾
  1. 气象特征:风速、风向(拆sin/cos)、温度、气压
  2. 时间特征:小时、月份、季节,同样做循环分解
  3. 滞后特征:取过去N个时刻的值,反映短期惯性
  4. 滚动窗口特征:取一段时间的统计量,反映趋势和波动

记住:特征工程没有标准答案。不同风场、不同季节、不同机型,最优特征组合都不一样。多试、多调、多验证,才是王道。


公众号:蓝海资料掘金营,微信deep3321