4. 特征工程:气象特征提取与选择

大家好,我是老张。干风电这行十几年了,今天咱们聊聊特征工程。说白了,就是把原始气象数据变成模型能听懂的语言。这一步做不好,后面再牛的算法也白搭。

核心观点:特征工程不是简单的数据搬运,而是对物理规律的数学表达。我见过太多项目,模型调参调了三个月,最后发现是特征没选对。

4.1 气象特征提取:从传感器到特征

先说说最基本的四个气象要素:气压、温度、湿度、风向。嗯,这里要注意,原始数据不能直接用。

4.1.1 气压特征

气压变化能反映天气系统的移动。我个人习惯提取三个维度:

  • 瞬时气压:当前时刻的实测值,单位hPa
  • 气压变化率:过去1小时的变化量,ΔP/Δt
  • 相对气压:与同期历史均值的偏差

我的经验:有一次在海上风场,模型总是预报不准。后来发现是没考虑气压梯度力。加上相邻测站的气压差后,预测精度提升了12%。

4.1.2 温度特征

温度直接影响空气密度,进而影响风能。我建议这样处理:

  • 温度绝对值:注意传感器安装高度,一般取轮毂高度
  • 温度梯度:垂直方向温差,判断大气稳定度
  • 日温差:最高温与最低温的差值

4.1.3 湿度特征

湿度对空气密度影响很大。湿空气比干空气轻,你想想看,同样的风速,湿度大的时候发电量会少一些。

湿度范围 对空气密度影响 建议处理方式
<40% 可忽略 直接使用
40%-80% 中等 需校正
>80% 显著 必须考虑

4.1.4 风向特征

风向是环形变量,0°和360°其实是同一个方向。直接输入数值会出问题。

# 风向的正弦余弦编码
import numpy as np

def wind_direction_encoding(degrees):
    """将风向转换为正弦余弦特征"""
    rad = np.deg2rad(degrees)
    sin_component = np.sin(rad)
    cos_component = np.cos(rad)
    return sin_component, cos_component

# 示例:风向270°(西风)
sin_val, cos_val = wind_direction_encoding(270)
print(f"正弦分量: {sin_val:.3f}, 余弦分量: {cos_val:.3f}")
# 输出:正弦分量: -1.000, 余弦分量: 0.000

避坑指南:我曾经直接把风向度数喂给模型,结果模型死活学不会。后来才意识到,350°和10°明明只差20°,但数值上差了340°。用正弦余弦编码后,问题迎刃而解。

4.2 时序特征构建:让模型记住历史

风电预测本质上是时间序列问题。模型需要知道过去发生了什么,才能预测未来。

4.2.1 滑动窗口特征

我最常用的方法:取过去N个时间步的统计量。

def create_window_features(df, window_size=6):
    """构建滑动窗口特征"""
    features = pd.DataFrame()
    
    # 均值特征
    features['wind_speed_mean_6h'] = df['wind_speed'].rolling(window_size).mean()
    
    # 最大值特征
    features['wind_speed_max_6h'] = df['wind_speed'].rolling(window_size).max()
    
    # 趋势特征(线性拟合斜率)
    def trend_slope(series):
        x = np.arange(len(series))
        if len(series) < 2:
            return 0
        slope, _ = np.polyfit(x, series, 1)
        return slope
    
    features['wind_speed_trend_6h'] = df['wind_speed'].rolling(window_size).apply(trend_slope)
    
    return features

4.2.2 时间编码特征

风电有很强的日周期和年周期。我建议加入:

  • 小时的正弦余弦:24小时周期
  • 月份的正弦余弦:12个月周期
  • 季节标志:0/1/2/3 四分类

4.2.3 滞后特征

为什么用滞后特征?因为大气运动有惯性。今天的风速和昨天的风速高度相关。

# 构建滞后特征
def create_lag_features(df, lags=[1, 3, 6, 12, 24]):
    """构建滞后特征"""
    for lag in lags:
        df[f'wind_speed_lag_{lag}h'] = df['wind_speed'].shift(lag)
    return df

4.3 特征选择方法:去粗取精

特征不是越多越好。我见过有人搞了200多个特征,结果模型过拟合得一塌糊涂。

4.3.1 过滤法

先算相关性,把明显没用的特征剔除。

方法 原理 适用场景
皮尔逊相关系数 线性相关 连续变量
互信息 非线性相关 复杂关系
方差阈值 低方差剔除 常数特征

4.3.2 包裹法

用模型本身来选特征。我个人喜欢用递归特征消除(RFE)。

from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestRegressor

# 递归特征消除
estimator = RandomForestRegressor(n_estimators=100)
selector = RFE(estimator, n_features_to_select=10, step=1)
selector.fit(X_train, y_train)

# 查看选中的特征
selected_features = X_train.columns[selector.support_]
print(f"选中的特征: {list(selected_features)}")

4.3.3 嵌入法

L1正则化(Lasso)自带特征选择功能。它会自动把不重要的特征系数压到0。

from sklearn.linear_model import Lasso

# Lasso特征选择
lasso = Lasso(alpha=0.01)
lasso.fit(X_train, y_train)

# 系数非零的特征
important_features = X_train.columns[lasso.coef_ != 0]
print(f"重要特征: {list(important_features)}")

我的建议:三种方法结合使用。先用过滤法粗筛,再用包裹法精挑,最后用嵌入法验证。我在西北某风场就是这么做的,特征从50个降到12个,模型精度反而提升了8%。

4.4 知识体系总览

下面这张图,是我梳理的特征工程整体流程。你仔细看看,每一步都有讲究。

气象特征工程知识体系 原始气象数据 特征提取 气压特征 温度特征 湿度特征 风向特征 时序特征构建 滑动窗口特征 时间编码特征 滞后特征 特征选择 过滤法(相关性) 包裹法(RFE) 嵌入法(Lasso)

这张图展示了特征工程的完整链路。从原始数据出发,经过提取、构建、选择三步,最终得到高质量的特征集。每一步都有对应的技术方法,咱们刚才都讲到了。

总结一下:特征工程是风电预测的基石。气压、温度、湿度、风向这四个基础特征要处理到位,时序特征要构建合理,特征选择要讲究方法。我在实际项目中,花在特征工程上的时间通常占整个项目的60%以上。这一步做扎实了,后面的建模就是水到渠成的事。

专注资料整理