简介这份资源是面向气候科学领域的机器学习端到端管道项目适合具备一定Python基础、希望用机器学习方法预测与理解干旱的研究者与学习者。项目围绕统一数据格式的构建、方法对比与评估展开将数据准备、训练与测试等任务拆分为src目录下的不同类便于按模块理解与复用并配套说明管道目标与设计的博客文章及初始介绍。压缩包为zip格式整体约49.31MB文件类型以Jupyter Notebook为主辅以Python源码与conda环境配置可用于搭建可复现的实验环境。已有142人学习下载读者可从中获得一套结构清晰的气候机器学习流程参考包括数据统一化处理思路、方法相互比较与评估的组织方式以及基于Copernicus相关数据的实践入口适合作为干旱预测方向课题的起步模板与代码骨架。1. 干旱预测为什么值得用机器学习重做一遍如果你做过气象或水文方向的数据分析大概率遇到过这种尴尬传统干旱指数比如 SPI、SPEI算出来是一条平滑的曲线看着挺规整但真到业务上问一句「下个月这片区域会不会进入干旱」它答不上来。干旱本质上是降水、蒸散、土壤含水量、温度多个变量耦合出来的慢过程线性指标很难把这种非线性滞后关系吃透。ml_drought这个资源包走的就是另一条路用 Copernicus 体系下的再分析/观测数据做特征拿机器学习模型去拟合干旱指数或干旱等级把「事后描述」往「事前预测」推一步。它面向的是已经会用 pandas 读 NetCDF、想把手上的气候数据真正跑成模型的人不是纯理论科普。整套东西以 Jupyter Notebook 组织2019 年前后那批 Copernicus 气候数据服务的数据产品是它的主要数据来源所以你会看到不少围绕 ERA5、卫星降水这类格点数据的预处理痕迹。2. 拆开资源包Notebook 里到底装了什么拿到一个以 Notebook 为主的资源包最忌讳上来就从头到尾 Run All。先花十分钟把目录结构和每个 notebook 的职责摸清楚后面调参和排错才有抓手。ml_drought的组织方式比较典型数据准备、特征工程、模型训练、评估可视化各占一块中间靠中间文件csv / npz / pkl串起来。这种「分阶段落盘」的设计对复现特别友好因为你可以只重跑出错的那一段不用每次从读原始格点数据开始。2.1 目录结构与各 Notebook 职责常见做法是按编号命名比如01_data_prep.ipynb、02_features.ipynb、03_train.ipynb、04_eval.ipynb。我一般会先建一张职责表把每个 notebook 的输入、输出、依赖的库版本记下来避免跑到一半发现某个中间文件对不上。阶段典型输入典型输出关键依赖数据准备原始格点数据NetCDF/GRIB区域裁剪后的 csv 或 npzxarray、netCDF4、pandas特征工程上一步的表格数据带滞后项/滑动窗口的特征表pandas、numpy模型训练特征表 标签训练好的模型 pklscikit-learn / xgboost评估可视化模型 测试集指标表、混淆矩阵、时间序列图matplotlib、seaborn这张表不是摆设。等你后面发现「评估图怎么跟训练日志对不上」回头一看往往是特征表版本和模型 pkl 不是同一次生成的。把每个阶段的产物命名带上时间戳或参数后缀是省后悔药的最简单办法。2.2 数据来源与字段含义资源包围绕 Copernicus 气候数据服务展开核心变量一般包括降水、2 米气温、潜在蒸散、土壤湿度分层数据。这些变量在原始格点文件里通常是三维的时间 × 纬度 × 经度落到建模前必须压成「样本 × 特征」的二维表。字段命名上要特别小心不同数据产品对同一物理量的缩写不一样比如降水可能叫tp、pr或precip单位还可能是 m/day 和 mm/day 混着来。我一般会在数据准备阶段就统一成一套命名和单位写进一个rename_map字典里后面所有 notebook 都引用它避免同一个变量在三个文件里三种叫法。import xarray as xr import pandas as pd # 统一变量名与单位避免后续 notebook 各叫各的 rename_map { tp: precip, # 总降水 t2m: temp_2m, # 2 米气温 pev: pet, # 潜在蒸散 } unit_scale { precip: 1000.0, # m/day - mm/day temp_2m: 1.0, # K保持原样后续再转摄氏度 pet: 1000.0, } ds xr.open_dataset(raw_climate.nc) ds ds.rename({k: v for k, v in rename_map.items() if k in ds}) for var, scale in unit_scale.items(): if var in ds: ds[var] ds[var] * scale这段代码的逻辑很直白先重命名再按变量做单位换算。参数上要注意unit_scale只对需要换算的变量生效温度这里故意不转摄氏度是因为后面做特征时可能还要用开尔文算饱和水汽压提前转反而多一步。跑完这一步建议立刻ds[[precip,temp_2m]].isel(time0).to_dataframe()抽一个时次看看数值范围降水日值在 0 到几十 mm 之间算正常如果出现几百多半是单位没换对。3. 从格点数据到可训练特征预处理与特征工程干旱预测的模型效果七成取决于特征怎么构造三成才是选什么算法。原始格点数据直接喂给模型基本没戏必须做区域裁剪、时间聚合、滞后特征和滑动窗口统计。这一章把这条链路拆成可抄的步骤每一步都给出参数含义和常见取值。3.1 区域裁剪与时间聚合全球格点数据动辄几十 GB先按研究区经纬度范围裁一刀能省掉大量 IO 时间。裁剪之后按需要聚合到月尺度或旬尺度干旱本身是慢变量日尺度噪声大且样本冗余。常见做法是用xarray的sel做切片再用resample做时间重采样。# 按经纬度范围裁剪再聚合到月尺度 ds_region ds.sel( latitudeslice(40, 25), # 注意纬度可能是降序先确认坐标方向 longitudeslice(100, 120), ) ds_monthly ds_region.resample(time1MS).mean() # 月平均 precip_monthly ds_region[precip].resample(time1MS).sum() # 降水用求和这里有两个容易翻车的点。第一纬度切片方向很多再分析产品的纬度是从北到南递减的slice(40, 25)和slice(25, 40)结果完全不同跑之前先print(ds.latitude.values[:5])确认。第二不同变量的聚合方式不一样气温用平均、降水用求和混用会让特征物理意义全错。聚合完把结果to_dataframe().reset_index()落成 csv后面特征工程就不用再碰 NetCDF 了。3.2 滞后特征与滑动窗口构造干旱的预测价值在于「提前量」所以特征里必须包含历史信息。常用构造是当前月往前推 1 到 6 个月的降水、温度加上 3 个月和 6 个月滑动累计降水。标签可以是当前或未来 1 到 3 个月的干旱指数分级。用 pandas 的shift和rolling就能搭出来。df pd.read_csv(monthly_region.csv, parse_dates[time]) df df.sort_values([lat, lon, time]) # 按格点分组构造滞后与滑动特征 for lag in [1, 2, 3, 6]: df[fprecip_lag{lag}] df.groupby([lat, lon])[precip].shift(lag) df[precip_roll3] ( df.groupby([lat, lon])[precip] .transform(lambda s: s.rolling(3, min_periods3).sum()) ) df[temp_roll3] ( df.groupby([lat, lon])[temp_2m] .transform(lambda s: s.rolling(3, min_periods3).mean()) ) # 标签未来第 1 个月的干旱等级示例用分位数离散化 df[label] df.groupby([lat, lon])[precip_roll3].shift(-1) df df.dropna()逻辑说明groupby([lat,lon])保证滞后和滑动只在同一格点内进行不会跨空间串数据这是最容易忽略的一步。min_periods3强制窗口不满就不出值避免前期用不完整窗口算出偏小的累计量。标签用shift(-1)取未来一个月注意方向是负的写成正的就变成「用未来预测过去」模型指标会好得离谱但毫无意义。参数上滞后阶数不是越多越好6 阶以上在样本量有限时容易过拟合我一般先用 1、2、3、6 这四档试。3.3 训练集/测试集的时间切分气候数据有时间自相关随机切分会让相邻月份同时出现在训练和测试里指标虚高。正确做法是按时间切前 70% 到 80% 的年份训练后段测试中间可以留一段做验证。这一步没有代码块的必要但必须写进流程切分点一旦定下就固定住所有模型用同一套切分否则模型之间没法比。4. 模型训练与评估选型、参数与指标解读到了训练环节资源包一般会给几个基线模型做对比常见的是线性回归、随机森林、梯度提升树XGBoost / LightGBM 这一类。干旱预测这种表格型特征、样本量中等的任务树模型往往比深度学习更稳调参成本也低。这一章讲怎么把训练跑通、参数怎么设、指标怎么看。4.1 基线模型与树模型对比先用线性回归跑一个基线不是为了效果好是为了知道「线性关系能解释多少」。如果树模型比线性基线提升很小说明特征里非线性信息不足该回去补特征而不是继续调参。树模型这边随机森林适合快速看特征重要性梯度提升树在调好学习率和树深后通常精度更高。from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, r2_score import numpy as np feature_cols [c for c in df.columns if c.startswith((precip_, temp_))] split_year 2015-01-01 train df[df[time] split_year] test df[df[time] split_year] rf RandomForestRegressor( n_estimators300, # 树数量300 起步够用 max_depth12, # 控制过拟合样本少时降到 8 min_samples_leaf5, # 叶节点最小样本防止记住噪声 random_state42, n_jobs-1, ) rf.fit(train[feature_cols], train[label]) pred rf.predict(test[feature_cols]) rmse np.sqrt(mean_squared_error(test[label], pred)) print(RMSE:, round(rmse, 3), R2:, round(r2_score(test[label], pred), 3))参数说明n_estimators增大到一定程度收益递减300 到 500 是常见区间max_depth是控制过拟合的主要旋钮气候样本通常几千到几万条深度超过 15 基本就是在记训练集min_samples_leaf设 5 左右能明显平滑预测。评估时 RMSE 要和标签的量纲对齐看如果标签是标准化后的值RMSE 0.3 和原始 mm 单位的 0.3 完全不是一回事报告里一定写清楚。4.2 特征重要性与物理解释树模型能给特征重要性但别把它当因果。重要性高只说明这个特征在划分时被用得多不代表物理上一定关键。我一般会把重要性排序和滞后阶数对照看如果precip_lag1和precip_roll3都排前面符合干旱对近期降水的依赖说明特征构造方向对如果某个温度滞后项异常突出就要回头查是不是数据里有缺测被填成了异常值。import pandas as pd imp pd.Series(rf.feature_importances_, indexfeature_cols) print(imp.sort_values(ascendingFalse).head(10))这段输出建议存成 csv 归档换模型、换特征集时对比着看比单看一次指标更能发现问题。4.3 分类任务下的指标陷阱如果标签做成干旱等级无旱/轻旱/中旱/重旱就变成分类问题这时候准确率是最坑的指标。干旱样本往往类别不平衡重旱样本少模型全预测「无旱」也能有 80% 准确率。要看的是重旱类的召回率和 F1混淆矩阵必须画出来。常见做法是对少数类做重采样或调class_weightbalanced但重采样只能在训练集上做测试集保持原始分布否则评估失真。5. 避坑与排查五个真实会翻车的点这一章是我自己拆这类资源包时踩过的坑按「现象 → 原因 → 解决」写照着排查能省不少时间。现象一模型 R² 高得离谱接近 0.99。原因基本是数据泄漏最常见的是标签shift方向写反或者标准化时用了全量数据导致测试集信息渗进训练。解决检查所有shift的符号标准化只在训练集上fit测试集只transform。现象二不同格点预测结果完全一样。原因是groupby时漏了空间维度滞后特征跨格点串了或者特征表合并时lat/lon精度不一致导致匹配失败。解决合并前把经纬度round(2)统一精度合并后抽查两个格点的特征值是否不同。现象三降水特征出现负值。原因是单位换算或插值方法用错比如对降水做了线性插值填补缺测插出负数。解决降水缺测用气候态或 0 填别用线性插值换算后加一句df[precip] df[precip].clip(lower0)兜底。现象四训练很快但预测时报特征数量不匹配。原因是训练和预测用了不同版本的特征表中间某次改了滞后阶数没同步。解决把feature_cols列表和模型 pkl 一起存盘预测时从 pkl 旁边读列表不要重新推导。现象五评估图的时间轴错乱。原因是resample后索引没排序或者时区信息丢失导致to_dataframe后时间列变成字符串。解决聚合后统一sort_index()落盘前pd.to_datetime再确认一次 dtype。提示这五条里前两条最隐蔽指标好看的时候反而要警惕先怀疑泄漏再高兴。6. 进阶把单点预测做成滚动预报并验证单次训练测试只能说明模型在历史切分上表现如何真正落地要看滚动预报每次用截至当前月的数据训练预测未来 1 到 3 个月然后窗口往前滚一个月重来。这个流程能暴露模型在时间上的稳定性也是判断「能不能用」的关键。我一般写一个小循环把每次滚动的指标记下来看趋势。results [] for cutoff in pd.date_range(2012-01-01, 2018-12-01, freq6MS): tr df[df[time] cutoff] te df[(df[time] cutoff) (df[time] cutoff pd.DateOffset(months3))] if len(te) 0: continue m RandomForestRegressor(n_estimators200, max_depth10, min_samples_leaf5, random_state42, n_jobs-1) m.fit(tr[feature_cols], tr[label]) p m.predict(te[feature_cols]) results.append({ cutoff: cutoff, rmse: np.sqrt(mean_squared_error(te[label], p)), n_test: len(te), }) res_df pd.DataFrame(results) print(res_df)这段循环的关键参数是freq6MS即每半年滚动一次样本少时可以改成 12 个月预测窗口 3 个月对应干旱的预报时效需求。跑完看rmse随cutoff的变化如果某几个时间点误差突然飙高回去查那段时间原始数据有没有缺测或产品版本切换。滚动验证比单次切分更接近业务真实场景也是我判断一个气候 ML 资源包值不值得继续投入的标准。从那以后我每次拆这类 Notebook 资源都强制先跑一遍滚动验证再谈调参单次指标再漂亮也不作数。希望帮到你。本文还有配套的精品资源点击获取