
简介这份资源面向数据科学竞赛入门者与气象数据分析爱好者围绕天气预测这一典型时间序列建模任务提供了一套可直接上手的竞赛项目素材。包内共9个文件以4个xml配置、2个csv数据表、1个py脚本、1个h5模型文件及1个iml工程配置为主压缩包约7.12MB涵盖数据读取、模型训练与工程配置等环节便于快速复现完整流程。已有634人学习下载说明其在同类赛题中具备一定参考价值。读者可借助csv中的气象观测数据练习缺失值与异常值处理结合py脚本理解特征工程与建模思路并参考h5文件对比模型输出进而掌握线性回归、随机森林及LSTM等方法在温度、降雨概率、风速预测中的应用同时熟悉MSE、RMSE、MAE与R²等评估指标及交叉验证流程适合作为课程设计或竞赛练手的实战素材。1. 天气预测竞赛资源包拆解从 train_v2.csv 到 weather_v2.h5 的完整链路如果你手头正好有一个叫天气预测.rar的压缩包解压后看到competition_weather_forecast-master、train_v2.csv、weather.csv、weather_v2.h5、handle_v2.py这一串文件大概率会先愣一下这到底是一份能直接跑通的竞赛方案还是别人中途弃坑的半成品我拆过不少这类竞赛包说实话大部分都卡在“数据格式对不上”和“预处理脚本跑不通”这两步上。这份资源的核心价值在于它把原始气象观测数据、清洗脚本和中间态 HDF5 文件放在了一起等于把一条从 CSV 到模型输入的流水线摊开给你看。适合谁用如果你正在打时间序列类的数据竞赛或者想找一个带真实缺失值、多字段气象指标的数据集练手特征工程这个包能省掉你从零爬数据、对齐时间戳的功夫。但别指望它自带一个调好参的 LSTM 模型——handle_v2.py才是重点它决定了你后面能不能把weather_v2.h5喂进网络。2. 先搞懂数据分层train_v2.csv、weather.csv 和 weather_v2.h5 到底谁是谁2.1 三个数据文件的角色划分与字段推断拿到包先别急着python handle_v2.py把三个数据文件的关系理清楚后面能少走很多弯路。从命名和常见竞赛套路来看train_v2.csv是带标签的训练集主表通常包含时间戳、站点编号、以及温度、湿度、气压、风速、降水量这些观测值最后一列或某几列是你要预测的目标变量。weather.csv更像是原始观测记录或者补充气象站数据字段可能更全但缺失值也更多用来做特征扩充。而weather_v2.h5是 HDF5 格式的中间产物一般是handle_v2.py跑完之后生成的里面存的是已经对齐时间步、填充缺失值、甚至做过归一化的数组直接可以被 Pandas 的read_hdf或者 Keras 的Sequence读取。为什么要有 HDF5 这一层CSV 读起来慢尤其是时间序列做滑动窗口的时候反复解析文本开销很大。HDF5 是二进制列式存储读一个 100 万行的浮点数组比 CSV 快一个数量级而且支持分块压缩。我一般会在预处理阶段就把数据转成 HDF5后面调参的时候省下来的时间够多跑好几组实验。提示先别删weather.csv哪怕你觉得它字段冗余。很多竞赛的测试集里会混入只有weather.csv才有的气象指标删了就补不回来了。2.2 用 Pandas 快速摸清数据规模和缺失情况在跑任何脚本之前花五分钟做一次数据体检。下面这段代码直接抄把三个文件的基本信息打出来import pandas as pd import h5py # 读训练集nrows 先只读前 5000 行看结构避免大文件卡住 train pd.read_csv(train_v2.csv, nrows5000) print(train_v2.csv 形状:, train.shape) print(字段列表:, train.columns.tolist()) print(前 3 行:\n, train.head(3)) print(缺失值占比:\n, train.isnull().mean().sort_values(ascendingFalse).head(10)) # weather.csv 同样先采样 weather pd.read_csv(weather.csv, nrows5000) print(\nweather.csv 形状:, weather.shape) print(字段列表:, weather.columns.tolist()) # HDF5 文件用 h5py 看内部结构不要直接 read_hdf 猜 key with h5py.File(weather_v2.h5, r) as f: def print_h5(name, obj): if isinstance(obj, h5py.Dataset): print(f数据集: {name}, 形状: {obj.shape}, 类型: {obj.dtype}) f.visititems(print_h5)逻辑说明nrows5000是为了防止 CSV 太大直接把内存吃满先看字段名和缺失分布。isnull().mean()按列算缺失比例排在前面的就是后面预处理要重点处理的列。HDF5 部分用h5py遍历而不是pd.read_hdf是因为你还不确定里面存的是 DataFrame 还是纯 numpy 数组visititems能把所有数据集的形状和类型列出来避免 key 猜错报KeyError。参数怎么改如果你的train_v2.csv超过 5000 行且字段很多把nrows调到 20000 再看一遍确保没漏掉稀疏字段。缺失值占比超过 40% 的列后面要么做插值要么直接丢别硬填均值。3. handle_v2.py 逐段拆解预处理脚本里的四个关键操作3.1 时间戳对齐与重采样逻辑handle_v2.py是整个包里最值得细读的文件。我拆过类似脚本核心操作通常就四步时间戳解析、按站点分组、缺失值插补、滑动窗口构造。先看时间戳对齐气象数据最常见的问题是不同站点上报频率不一样有的每小时一条有的三小时一条直接合并会出现大量 NaN。import pandas as pd import numpy as np def align_timestamp(df, time_coltimestamp, freq1H): # 强制转 datetimeerrorscoerce 把解析失败的变成 NaT方便后面统计 df[time_col] pd.to_datetime(df[time_col], errorscoerce) # 按站点分组后重采样到统一频率取均值聚合 df df.set_index(time_col).groupby(station_id).resample(freq).mean() # 重采样后索引是多级把 station_id 还原成列 df df.reset_index() return df train pd.read_csv(train_v2.csv) train align_timestamp(train, freq1H) print(重采样后形状:, train.shape) print(各站点记录数:\n, train.groupby(station_id).size().describe())逻辑说明pd.to_datetime加errorscoerce是血泪经验气象数据里经常混着2023-01-01 00:00:00和2023/1/1 0:00两种格式不统一转后面全乱。groupby(station_id).resample(1H)保证每个站点独立按小时对齐不会把不同站点的数据混在一起。.mean()是默认聚合如果你预测的是降水量可能要改成.sum()这个得看目标变量定义。参数怎么改freq1H可以改成3H或1D取决于竞赛要求的预测粒度。如果原始数据是分钟级改成1H相当于降采样能减少噪声但会丢高频信息。重采样后如果某个站点记录数明显偏少检查它的时间戳是不是解析失败了。3.2 缺失值插补与异常值裁剪重采样之后必然出现 NaN因为原始数据不可能每个小时都有记录。handle_v2.py里大概率用了前向填充加线性插值的组合我一般也这么干def fill_missing(df, cols_to_fill): df df.sort_values([station_id, timestamp]) # 先按站点分组做前向填充再后向填充兜底 df[cols_to_fill] df.groupby(station_id)[cols_to_fill].transform( lambda x: x.ffill().bfill() ) # 对温度、气压这类连续变量做线性插值限制最大插补间隔 for col in cols_to_fill: df[col] df.groupby(station_id)[col].transform( lambda x: x.interpolate(methodlinear, limit6) ) return df cols [temperature, humidity, pressure, wind_speed] train fill_missing(train, cols) print(插补后剩余缺失:\n, train[cols].isnull().sum())逻辑说明ffill().bfill()是先用前一个有效值填再反向填适合变化缓慢的气象变量。interpolate(methodlinear, limit6)限制最多连续插 6 个点超过 6 小时的空缺说明设备可能离线了硬插会引入虚假趋势。limit6这个参数根据你的数据频率调如果是小时数据6 小时以内的空缺插值还算合理。异常值裁剪别忘掉温度出现 200 度、风速出现负数都是传感器故障。常见做法是用 IQR 或者 3σ 截断def clip_outliers(df, col, n_sigma3): mean, std df[col].mean(), df[col].std() lower, upper mean - n_sigma * std, mean n_sigma * std df[col] df[col].clip(lower, upper) return df for c in cols: train clip_outliers(train, c)3.3 滑动窗口构造与 HDF5 落盘预处理最后一步是把时序数据切成模型能吃的样本。假设你要用过去 24 小时预测未来 1 小时温度窗口构造如下def make_windows(data, feature_cols, target_col, window_size24, horizon1): X, y [], [] for station, group in data.groupby(station_id): values group[feature_cols].values targets group[target_col].values for i in range(len(values) - window_size - horizon 1): X.append(values[i:iwindow_size]) y.append(targets[iwindow_sizehorizon-1]) return np.array(X), np.array(y) feature_cols [temperature, humidity, pressure, wind_speed] X, y make_windows(train, feature_cols, temperature, window_size24, horizon1) print(X 形状:, X.shape, y 形状:, y.shape) # 落盘成 HDF5方便后面直接读 import h5py with h5py.File(weather_v2.h5, w) as f: f.create_dataset(X, dataX, compressiongzip) f.create_dataset(y, datay, compressiongzip)逻辑说明window_size24表示用 24 个时间步作为输入horizon1表示预测未来第 1 步。groupby(station_id)保证窗口不会跨站点滑动否则会把 A 站的数据和 B 站拼在一起。compressiongzip能显著减小 HDF5 体积代价是读写稍微慢一点但比 CSV 还是快得多。参数怎么改window_size和horizon是调参重点。预测温度这种周期性强的变量窗口开到 48 或 72 可能更好预测降水这种稀疏事件窗口太大反而引入噪声。落盘前先print(X.shape)确认样本数没少如果某个站点数据太短窗口构造会跳过它样本数对不上就查站点记录数。4. 避坑与排查跑不通 handle_v2.py 时先看这五条4.1 现象pd.read_csv报UnicodeDecodeError原因气象数据里站点名或备注字段可能混了 GBK 编码的中文默认 UTF-8 解不了。解决加encodinggbk或encodingutf-8-sig试一遍还不行就用chardet检测。4.2 现象重采样后数据量暴增内存直接爆原因resample(1H)如果原始时间戳跨度很大但记录稀疏会生成大量空行。解决先按站点算时间跨度对记录数过少的站点直接过滤或者把freq改成3H降低密度。4.3 现象HDF5 文件读出来全是 NaN原因插补步骤在落盘之前没执行或者fill_missing的列名和实际字段对不上。解决在create_dataset之前加一行assert not np.isnan(X).any()有 NaN 直接报错定位。4.4 现象模型训练 loss 不下降RMSE 卡在均值附近原因特征没做归一化温度范围 0-40 和气压 1000-1020 量纲差太大。解决在窗口构造前对每个特征做(x - mean) / std注意用训练集的均值和方差别用全量数据。4.5 现象weather.csv和train_v2.csv合并后字段冲突原因两个表有同名字段但含义不同比如都叫temp但一个是摄氏度一个是华氏度。解决合并前先rename加后缀或者只取weather.csv里训练集没有的列。5. 进阶技巧用 weather_v2.h5 做时序交叉验证与模型快速迭代预处理跑通之后别急着上 LSTM。我一般先用weather_v2.h5里的数据跑一个轻量级的基线确认特征和窗口构造没问题再换复杂模型。时序数据的交叉验证不能随机打乱得用TimeSeriesSplitfrom sklearn.model_selection import TimeSeriesSplit from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error import h5py import numpy as np with h5py.File(weather_v2.h5, r) as f: X f[X][:] y f[y][:] # 把三维 (样本, 时间步, 特征) 展平成二维给树模型 X_flat X.reshape(X.shape[0], -1) tscv TimeSeriesSplit(n_splits5) rmse_scores [] for train_idx, val_idx in tscv.split(X_flat): model RandomForestRegressor(n_estimators100, max_depth10, n_jobs-1, random_state42) model.fit(X_flat[train_idx], y[train_idx]) pred model.predict(X_flat[val_idx]) rmse np.sqrt(mean_squared_error(y[val_idx], pred)) rmse_scores.append(rmse) print(f折 RMSE: {rmse:.4f}) print(f平均 RMSE: {np.mean(rmse_scores):.4f})逻辑说明TimeSeriesSplit保证训练集始终在验证集之前不会用未来数据预测过去。X.reshape(X.shape[0], -1)把 24 个时间步 × 4 个特征展成 96 维随机森林能吃这种扁平输入。max_depth10是防止过拟合的保守设置如果 RMSE 偏高再逐步放宽。参数怎么改n_splits5适合样本量几万条的情况样本少就降到 3。n_estimators100是起点加到 300 通常还能降一点但训练时间翻倍。如果你要上 LSTM把X直接喂进去但记得在handle_v2.py里加一步归一化树模型对量纲不敏感神经网络很敏感。还有一个技巧把weather.csv里训练集没有的字段按时间戳和站点合并进来哪怕缺失率高先加进去看特征重要性。我试过把气压趋势项当前气压减 3 小时前气压加进去RMSE 降了 0.3 左右这种衍生特征比换模型管用。从那以后我每次拿到竞赛包都强制先跑一遍数据体检和基线验证确认handle_v2.py的输出和weather_v2.h5对得上再动模型结构。希望帮到你。本文还有配套的精品资源点击获取