ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

随机森林气温预测实战:从源码解析到调参避坑

随机森林气温预测实战:从源码解析到调参避坑 简介这是一份面向高校学生与开发者的随机森林气温预测项目源码适用于毕业设计、课程设计及机器学习入门实践。项目以Python实现借助Scikit-learn构建随机森林模型处理湿度、气压、风速等多变量与气温之间的复杂关系覆盖数据预处理、特征选择、模型训练与评估等完整流程帮助读者理解集成学习在时间序列预测中的应用。资源包共19个文件约4.23MB以py源码、csv数据集、xml配置、txt说明及zbak备份为主另含dot决策树可视化文件与zip附赠资料结构清晰便于按模块查阅。目前已有117人学习下载。通过研读源码与数据文件读者可掌握随机森林建模思路、参数调整与模型验证方法并熟悉从设计到测试的软件开发流程适合作为学习研究用途的参考范例。1. 从一份气温预测源码包说起随机森林到底能跑出什么结果很多同学做毕业设计时选题定到基于随机森林的气温预测第一反应是去搜现成源码结果下回来一堆跑不起来的压缩包。我手上这份temp-predict就是典型的一线课程设计产物Python 写的随机森林回归模型配套temps.csv和temps_extended.csv两份气象数据外加readdata.py、treeparam.py、predict.py三个核心脚本还有一个newsbayes.py是附赠的朴素贝叶斯分类示例。它解决的不是从零教你机器学习而是给你一套能直接跑通、能改参数、能写进论文实验章节的完整流程。适合谁用计算机、数据分析、人工智能方向做课程设计或毕业设计的同学以及想快速验证随机森林在时序气象数据上表现的开发者。不适合指望它直接产出商用气象服务的人——数据规模、特征工程深度都撑不起生产环境。但作为学习随机森林回归、理解特征重要性、练习 sklearn 调参的载体这份源码的完整度是够的。2. 拆开压缩包先看什么文件结构与数据字段的对应关系2.1 目录里每个文件到底干什么用拿到temp-predict这个包别急着python predict.py。先花五分钟把文件角色理清楚后面调参和排错会省很多事。根据目录结构和常见课程设计项目的组织方式各文件职责大致如下文件/目录作用是否核心readdata.py读取 CSV、做日期解析和特征列筛选核心先跑treeparam.py随机森林参数配置与模型训练入口核心predict.py加载模型、输出预测结果与评估指标核心temps.csv基础气温数据含日期、实际温度、预测温度、天气特征核心数据temps_extended.csv扩展版数据字段更多适合做特征对比实验辅助tree.dot决策树可视化输出文件可用 Graphviz 渲染辅助newsbayes.py朴素贝叶斯新闻分类示例与气温预测无关附赠stopwords.txt朴素贝叶斯用的停用词表附赠data.txt原始数据备份或说明性文本参考.idea/、*.imlPyCharm 工程配置不影响运行可忽略提示.idea和.iml是 IDE 自动生成的换到 VSCode 或命令行运行时直接无视不要因为找不到 PyCharm 就以为项目跑不了。2.2 数据字段与特征工程的对应temps.csv是这份源码的命脉。常见的气温预测数据集字段包括date、actual实际温度、forecast预报温度、temp_2前两天温度、temp_1前一天温度、average历史平均温度、friend朋友预测属于趣味特征。随机森林要做的就是把这些列拆成特征矩阵 X 和目标向量 y。import pandas as pd # 读取气温数据parse_dates 把 date 列直接转成 datetime 类型 features pd.read_csv(temps.csv, parse_dates[date]) # 构造年份、月份、星期几三个时间特征 features[year] features[date].dt.year features[month] features[date].dt.month features[day] features[date].dt.dayofweek # 查看字段类型和缺失情况 print(features.dtypes) print(features.isnull().sum())这段代码的逻辑是原始date列对树模型没有直接数值意义必须拆成可比较的数值特征。dt.dayofweek返回 0 到 6代表周一到周日比直接保留字符串日期有用得多。参数上parse_dates指定列名后 pandas 会自动解析省去手动pd.to_datetime。如果数据里日期格式不统一这一步会直接报错所以先print(features.head())确认格式是稳妥做法。2.3 特征与标签的拆分逻辑# 目标列是 actual其余数值列作为特征 labels features[actual] features features.drop([actual, date], axis1) # 独热编码处理天气类别列如 week 列 features pd.get_dummies(features) # 转成 numpy 数组供 sklearn 使用 import numpy as np features np.array(features) labels np.array(labels) print(特征矩阵形状:, features.shape) print(标签向量形状:, labels.shape)这里的关键决策是pd.get_dummies。气温数据里常有week这种类别列比如星期一星期二树模型不能直接吃字符串独热编码把它变成 0/1 向量。参数drop_first默认 False保留全部类别对随机森林影响不大因为树不依赖线性假设。features.shape打印出来应该是(样本数, 特征数)如果第二维是 0说明drop时把特征全删了检查列名拼写。3. 随机森林回归的建模流程从 train_test_split 到特征重要性3.1 训练集测试集划分与模型初始化数据理干净之后进入建模环节。treeparam.py的核心逻辑就是配置随机森林回归器并拟合。常见做法是用train_test_split按 8:2 切分random_state固定住保证每次结果可复现。from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor # 固定随机种子保证实验可复现 X_train, X_test, y_train, y_test train_test_split( features, labels, test_size0.2, random_state42 ) # 初始化随机森林回归器 rf RandomForestRegressor( n_estimators1000, # 树的数量 max_depthNone, # 不限制深度 min_samples_split2, # 节点分裂最小样本数 min_samples_leaf1, # 叶节点最小样本数 random_state42, n_jobs-1 # 用满所有 CPU 核心 ) rf.fit(X_train, y_train) print(训练集得分:, rf.score(X_train, y_train)) print(测试集得分:, rf.score(X_test, y_test))参数说明n_estimators1000是课程设计里常见的保守值树越多方差越小但训练时间线性增长。max_depthNone让树完全生长气温数据样本量通常不大过拟合风险可控。n_jobs-1在四核机器上能把训练时间压到单核的四分之一左右。score返回的是 R²越接近 1 越好但如果训练集 0.98、测试集 0.6说明过拟合了得回头调max_depth或加min_samples_leaf。3.2 预测与误差评估# 在测试集上预测 predictions rf.predict(X_test) # 计算绝对误差 errors abs(predictions - y_test) print(平均绝对误差:, round(np.mean(errors), 2), 度) # 计算平均绝对百分比误差 mape 100 * np.mean(errors / y_test) accuracy 100 - mape print(预测准确率:, round(accuracy, 2), %)abs(predictions - y_test)得到每个样本的绝对误差取均值就是 MAE。MAPE 把误差归一化到百分比更适合向答辩老师解释模型准不准。注意y_test里如果有 0 或接近 0 的温度值MAPE 会爆炸这时候改用 MAE 或 RMSE 更稳妥。我一般会同时打印三个指标避免单一指标误导。3.3 特征重要性排序与 tree.dot 可视化随机森林自带特征重要性输出这是它比单一决策树更适合写论文的地方——你能明确说前一天温度贡献了 60% 的预测能力。# 获取特征重要性 importances list(rf.feature_importances_) feature_list list(features.columns) if hasattr(features, columns) else [ff{i} for i in range(features.shape[1])] # 排序输出 feature_importances [(feature, round(importance, 4)) for feature, importance in zip(feature_list, importances)] feature_importances sorted(feature_importances, keylambda x: x[1], reverseTrue) for pair in feature_importances[:10]: print(特征: {:20} 重要性: {}.format(*pair))如果前面用了np.array(features)列名会丢失所以更稳妥的做法是保留 DataFrame 到 fit 之前再转数组或者单独存一份列名列表。tree.dot文件是export_graphviz的输出装好 Graphviz 后执行dot -Tpng tree.dot -o tree.png就能得到单棵决策树的结构图放论文里很直观。4. 避坑与排查这份源码跑不起来时先查这五处4.1 现象FileNotFoundError: temps.csv→ 原因工作目录不对 → 解决切到脚本所在目录这是最高频的翻车点。PyCharm 默认工作目录是项目根命令行运行python predict.py时工作目录是你当前终端所在路径。如果 CSV 和脚本不在同一层就会报找不到文件。解决方式有两种cd到temp-predict目录再运行或者在代码里用os.path.dirname(__file__)拼绝对路径。import os base_dir os.path.dirname(os.path.abspath(__file__)) csv_path os.path.join(base_dir, temps.csv) features pd.read_csv(csv_path, parse_dates[date])4.2 现象KeyError: actual→ 原因列名有空格或大小写不一致 → 解决先打印列名CSV 文件从不同系统导出时列名可能带 BOM 头或首尾空格。features.columns打印出来如果看到\ufeffactual或actual 就得先清洗features.columns features.columns.str.strip()。别凭记忆写列名先看再写。4.3 现象R² 为负数 → 原因特征里混入了 ID 列或标签泄漏 → 解决检查 drop 列表如果features里不小心保留了actual的衍生列或者把行号当特征模型在测试集上会表现得比均值预测还差R² 直接为负。检查features.columns里有没有明显不该出现的列确认drop([actual])执行成功。4.4 现象ModuleNotFoundError: No module named sklearn→ 原因环境没装 scikit-learn → 解决pip 安装并确认版本pip install scikit-learn pandas numpy python -c import sklearn; print(sklearn.__version__)建议用 0.24 以上版本老版本RandomForestRegressor的n_jobs参数行为有差异。如果用的是 Anacondaconda install scikit-learn更省事。4.5 现象训练极慢或内存溢出 → 原因n_estimators过大或数据未降维 → 解决先小规模验证n_estimators1000在几千条数据上通常几十秒内完成但如果temps_extended.csv有几万行且特征上百内存会吃紧。先把n_estimators降到 100 跑通流程确认无误再往上加。n_jobs-1在部分 Windows 环境下反而变慢改成n_jobs1对比一下。5. 把模型用出论文价值参数调优与结果呈现的两个技巧5.1 用 GridSearchCV 做一轮可写进论文的调参课程设计如果只跑默认参数答辩时容易被问你为什么选 1000 棵树。用GridSearchCV做一轮小网格搜索把过程写进论文说服力完全不同。from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [100, 300, 500], max_depth: [None, 10, 20], min_samples_leaf: [1, 2, 4] } rf RandomForestRegressor(random_state42, n_jobs-1) grid_search GridSearchCV( estimatorrf, param_gridparam_grid, cv5, # 5 折交叉验证 scoringneg_mean_absolute_error, verbose1 ) grid_search.fit(X_train, y_train) print(最优参数:, grid_search.best_params_) print(最优得分:, grid_search.best_score_)cv5表示 5 折交叉验证把训练集再切五份轮流验证比单次train_test_split更稳。scoring用负 MAE 是因为 sklearn 的评分函数统一越大越好负号只是取反。verbose1会打印进度网格大的时候能看出卡在哪一组。跑完把best_params_和best_score_截图放论文比空口说调过参扎实得多。5.2 预测结果可视化让误差曲线说话光有数字不够画一张实际温度 vs 预测温度的折线图答辩时一眼就能看出模型在哪些区间偏差大。import matplotlib.pyplot as plt plt.figure(figsize(12, 6)) plt.plot(y_test.values, label实际温度, alpha0.8) plt.plot(predictions, label预测温度, alpha0.8) plt.xlabel(测试样本序号) plt.ylabel(温度) plt.title(随机森林气温预测结果对比) plt.legend() plt.tight_layout() plt.savefig(prediction_result.png, dpi150) plt.show()alpha0.8让两条线半透明重叠部分能看出吻合程度。dpi150保证截图放论文里不糊。如果两条线在高温段分叉明显说明模型对极端值拟合不足可以在论文不足与改进一节里写未来可引入梯度提升树或增加历史同期特征。5.3 一个我踩过的坑别在测试集上反复调参刚做这类项目时我习惯每次改完参数就rf.score(X_test, y_test)看一眼调了十几轮后测试集得分很好看但换一份新数据直接崩。血泪经验是测试集只能用一次调参阶段看交叉验证得分最终模型定下来再跑测试集。从那以后我每次做课程设计都强制走一遍训练集切分 → 交叉验证调参 → 测试集最终评估的流程再也没在答辩时被问倒过。这份temp-predict源码的价值不在于模型多先进而在于它把数据读取、特征构造、模型训练、结果评估这条链路完整摆出来了改一改就能套到其他回归预测题目上。需要参考的同学可以按上面的步骤先跑通readdata.py再逐步替换成自己的数据。希望帮到你。本文还有配套的精品资源点击获取
返回列表