4. 特征工程(上):温度因子——积温、极端温度、昼夜温差
温度,是农产品建模里最绕不开的因子。你想想看,从种子发芽到果实成熟,温度几乎贯穿了作物的一生。我做了这么多年农业量化,坦白讲,温度特征做得好不好,直接决定了模型的上限。
这一章,咱们就专门聊聊温度因子的特征工程。我会把积温、极端温度、昼夜温差这三个核心维度拆开来讲。每个维度我都会给出具体的计算逻辑、代码实现,以及我在实际项目中踩过的坑。
4.1 积温:作物生长的“能量账户”
积温这个概念,说白了就是作物在整个生长期内积累的热量总和。每种作物都有自己的一套“温度账本”。比如水稻,从播种到抽穗,需要累计达到一定的温度总量,否则就长不好。
我个人习惯把积温分成三类来算:
- 活动积温:高于某个生物学下限温度(通常是10℃)的日均温之和。公式很简单:
GDD = Σ(T_avg - T_base),其中T_base一般取10℃。 - 有效积温:这个更精细一些。它只计算高于基点温度的部分。比如小麦的基点温度是3℃,那低于3℃的日子就不算数。
- 滑动积温:用滑动窗口来聚合。比如过去7天、15天的积温。这个特征在预测短期生长状态时特别有用。
核心要点:积温不是简单的累加。不同作物的基点温度不同,甚至同一作物不同生育期的基点温度也不同。做特征工程时,一定要先查清楚作物的生理参数。
来看一段代码,这是我常用的积温计算方式:
import pandas as pd
import numpy as np
def calc_gdd(tavg, tbase=10.0):
"""
计算活动积温(Growing Degree Days)
tavg: 日均温序列(℃)
tbase: 基点温度,默认10℃
"""
# 低于基点温度的部分归零
gdd = np.maximum(tavg - tbase, 0)
return gdd
# 示例:某站点2023年4月日均温数据
temps = [12.5, 14.3, 9.8, 16.1, 18.7, 11.2, 13.9]
gdd_values = calc_gdd(np.array(temps), tbase=10)
print("每日积温:", gdd_values)
print("累计积温:", np.sum(gdd_values))
我的经验:我在做东北玉米产量预测时,发现用滑动积温(比如过去30天累计)比用全年总积温效果更好。因为玉米的关键生长期就那么几个月,拉长窗口反而引入了噪声。
4.2 极端温度:作物的“生死线”
极端温度,就是那些超出作物耐受范围的温度事件。为什么会这样?因为作物在极端温度下,生理活动会严重受阻,甚至直接死亡。
我一般会构建以下几类极端温度特征:
- 极端高温天数:日最高温超过35℃的天数。对于水稻,抽穗期遇到连续3天以上35℃高温,结实率会大幅下降。
- 极端低温天数:日最低温低于0℃的天数。这个对果树和越冬作物影响极大。
- 热浪持续时长:连续高温的天数。比如连续5天超过35℃,才算一次热浪事件。
- 寒潮强度:低温的累积强度。可以用
Σ(T_base - T_min)来量化,T_base取作物耐受下限。
避坑指南:我曾经在苹果产区建模时,只用了极端高温天数,结果模型在春季霜冻年份完全失效。后来才意识到,春季的极端低温(晚霜)对苹果花期的伤害比夏季高温更致命。所以,极端温度特征一定要覆盖全生育期,不能只看某个季节。
代码实现也很直接:
def extreme_temp_features(tmax, tmin, heat_thresh=35, cold_thresh=0):
"""
构建极端温度特征
tmax: 日最高温序列
tmin: 日最低温序列
"""
features = {}
# 极端高温天数
features['heat_days'] = np.sum(tmax > heat_thresh)
# 极端低温天数
features['cold_days'] = np.sum(tmin < cold_thresh)
# 最长热浪持续天数
heat_streak = (tmax > heat_thresh).astype(int)
features['max_heat_streak'] = max_streak(heat_streak)
# 寒潮累积强度
cold_intensity = np.sum(np.maximum(0, cold_thresh - tmin))
features['cold_intensity'] = cold_intensity
return features
def max_streak(binary_series):
"""计算连续1的最大长度"""
streaks = np.diff(np.concatenate(([0], binary_series, [0])))
starts = np.where(streaks == 1)[0]
ends = np.where(streaks == -1)[0]
if len(starts) == 0:
return 0
return np.max(ends - starts)
4.3 昼夜温差:品质的“催化剂”
昼夜温差这个因子,很多人容易忽略。但你知道吗?昼夜温差对农产品品质的影响,有时候比积温还大。
举个例子,新疆的哈密瓜为什么甜?就是因为白天光合作用强,晚上呼吸作用弱,糖分积累得多。说白了,昼夜温差大,有利于干物质和糖分的积累。
我常用的昼夜温差特征有:
| 特征名称 | 计算公式 | 适用场景 |
|---|---|---|
| 日较差 | T_max - T_min | 通用,反映每日温差幅度 |
| 累积温差 | Σ(T_max - T_min) 生长期内 | 果实品质预测(糖度、着色) |
| 温差波动率 | std(T_max - T_min) 滑动窗口 | 评估温差稳定性 |
| 夜间低温累积 | Σ(T_base - T_min) 仅夜间 | 水稻灌浆期、果树花芽分化 |
关键洞察:昼夜温差不是越大越好。我在葡萄品质建模中发现,当温差超过18℃时,反而会导致果皮开裂。所以,温差特征最好配合阈值处理,或者做分箱处理。
代码示例:
def diurnal_temp_features(tmax, tmin, window=7):
"""
构建昼夜温差特征
"""
diurnal_range = tmax - tmin
features = {}
# 平均日较差
features['mean_diurnal'] = np.mean(diurnal_range)
# 累积温差
features['cum_diurnal'] = np.sum(diurnal_range)
# 温差波动率(7天滑动标准差)
features['diurnal_volatility'] = (
pd.Series(diurnal_range).rolling(window).std().iloc[-1]
)
# 夜间低温累积(假设T_base=15℃)
night_cold = np.maximum(15 - tmin, 0)
features['night_cold_sum'] = np.sum(night_cold)
return features
4.4 特征组合与交互
单一的温度因子往往不够。我习惯把积温、极端温度和昼夜温差组合起来,构建交互特征。比如:
- 积温 × 温差:反映热量和温差对品质的协同效应
- 极端高温天数 × 积温:评估高温胁迫下的有效热量
- 温差波动率 × 极端低温:判断温度剧烈波动对作物的双重打击
我的习惯:交互特征不要盲目做。我一般先用随机森林或XGBoost跑一遍,看哪些原始特征重要,然后再针对重要特征做交互。这样能避免维度爆炸。
嗯,温度因子的特征工程,核心就是这三板斧:积温算总量,极端温度抓风险,昼夜温差看品质。下一章我们会继续聊水分因子——降雨、湿度、干旱指数。不过那是后话了,先把温度这块吃透再说。
本章小结:温度因子特征工程的三条主线——积温(能量账户)、极端温度(生死线)、昼夜温差(品质催化剂)。每个维度都要结合作物生理特性来设计,不能生搬硬套。