尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

随机森林回归实现水稻产量预测:Python源码与特征工程实战

发布时间:2026/9/23 21:18:17

资讯中心
01
ARTICLE

随机森林回归实现水稻产量预测:Python源码与特征工程实战

随机森林回归实现水稻产量预测:Python源码与特征工程实战
简介这份压缩包提供水稻产量预测的随机森林模型Python源码面向数据科学与大数据技术、人工智能、计算机等专业学生适合作为课程设计、大作业或毕业设计的实战参考也可用于机器学习入门练习。资源包含8个文件核心为Python脚本与两个CSV数据文件分别承载模型训练与预测结果对比另附项目配置相关的xml和iml文件整体包体仅54KB轻量易部署。已有203人学习下载可见其选题具有较高关注度。通过源码可掌握随机森林在回归任务中的完整流程包括数据读取、特征处理、模型训练、精度评估与预测可视化并可直接替换数据迁移至其他产量或销量预测场景对理解集成学习与工程化实现具有实用价值。1. 水稻产量预测为什么我推荐用随机森林一份能直接跑的Python源码思路水稻产量预测这事真正做起来跟想象中差距很大。你手上有过去十几年的气象数据、土壤数据和田间管理记录想预判今年产量线性回归发现残差很大神经网络又因为样本量太小直接欠拟合。这时候随机森林模型反而是最稳的选择它能吃下非线性关系对异常值和缺失值不太敏感训练完还能直接告诉你哪些因素最重要。这篇笔记就是基于一套随机森林模型Python源码的完整落地过程从特征构建、数据清洗到训练、调参、保存模型再到跨年验证和踩坑记录照着做就能把产量预测从“玄学”变成一份可复现的基线方案。适合农学背景的研究生、农业公司的数据分析岗以及刚入门机器学习想找一个真实回归场景练手的Python开发者。2. 随机森林回归的核心逻辑与水稻产量特征体系知道模型怎么想才知道特征怎么给2.1 随机森林回归比线性模型强在哪非线性、抗噪与特征重要性随机森林是Bagging思想下的决策树集成。回归任务里它训练出一批决策树每棵树在训练集的一个自助采样子集上生长分裂时又只随机挑一部分特征参与候选最终预测值是所有树预测结果的平均。这两处随机性带来了两个直接好处单棵树深到过拟合多棵树平均之后方差被压下去特征之间的共线性不会像线性回归那样伤系数因为每棵树都在用不同的特征组合做分裂。产量预测的场景里气象因子之间存在明显的协同关系比如某段时期的降水和温度共同决定分蘖数线性模型很难把这种交互项全部手工构造出来随机森林却能在训练中自动逼近这种结构。另一个更实际的优点是抗噪。大田数据不是实验室数据某个站点某年的日照时数可能因为传感器故障变成一个明显离谱的异常值个别地块的产量记录也可能因为收割损耗偏低。线性模型会把这种异常点当成趋势的一部分去拟合随机森林因为每棵树只见过一部分样本异常点对整体预测的影响被天然稀释。训练结束之后feature_importances_能直接输出每个特征的贡献占比这个能力对产量预测尤其有价值——领导或导师看完模型精度之后下一步一定会问“到底什么影响了产量”随机森林给了你一个可解释的入口。产量预测的样本量通常很小一个县往往只有二三十个站点乘十几年的记录几百条样本已经算充裕。这种规模下深层神经网络容易过拟合SVM对核函数和参数缩放又太敏感随机森林几乎不需要做特征标准化类别型变量也能直接编码后塞进去。这也是我建议把这个模型作为产量预测第一版基线的核心原因跑通快、可解释、不容易翻车。2.2 水稻产量预测的特征工程气象、土壤、田间管理三路数据怎么组织模型再强特征给不对也是白搭。水稻产量预测的特征体系常见做法是分成三路来组织气象、土壤、田间管理。每一路都要落到“站点 × 年份”这个粒度上也就是说最后喂给模型的一行数据要能对应上某个站点在某一年的产量记录。气象数据要按水稻生育期做聚合而不是直接丢月均值。籼稻和粳稻的生育期长度不同一个通用的做法是把全生育期拆成三个窗口营养生长期播种到拔节、生殖生长期拔节到抽穗、灌浆成熟期抽穗到收获。每个窗口分别计算平均温度、最高温均值、最低温均值、降水量累计、日照时数累计。如果不清楚具体物候期至少也要按“移栽后前60天、中间40天、后40天”这样的固定窗口切分否则模型学到的是全年的平均气候跟产量之间的因果关系非常模糊。土壤特征主要取整地前的理化指标有机质含量、pH值、全氮、速效钾、有效磷。这些数据通常不是每年都测常见做法是取站点最近一次实测值缺失年份直接前向填充而不是填均值。田间管理变量包括播种日期换算成年积日、氮肥施用量、栽插密度、灌溉方式。特别提醒一点同一块田的产量会受前一季作物影响如果有条件把“前茬作物类型”也做成一列类别特征对预测精度有明显提升。特征全部汇总之后最终的数据横向看起来像这样特征类别具体字段示例聚合方式气象t1_avg, t2_avg, t3_avg三个生育窗口平均温度气象rain1_sum, rain2_sum, rain3_sum三个窗口降水累计气象sun1_sum, sun2_sum, sun3_sum三个窗口日照累计土壤soil_om, soil_pH, soil_n最新一次实测值前向填充管理seed_doy, n_fertilizer, density播种年积日、施氮量、栽插密度这里有一个容易踩的隐性坑把站点ID直接当成特征丢进模型。随机森林对高基数类别特征有偏好站点ID参与分裂会严重干扰特征重要性排序。处理办法是把站点所在区域的纬度、经度、海拔作为数值特征放进去让模型自己去学地理位置带来的气候差异而不是记住“某个站点就是高产或低产”。实际测试下来去掉站点ID之后模型的测试集表现不但没有下降特征重要性的可解释性反而提升了一大截。3. 用Python源码跑通产量预测数据划分、随机森林训练与模型保存3.1 建训练集之前数据清洗与特征按时间聚合拿到原始数据之后不要急着把CSV丢进随机森林。第一件要做的事是画一条时间线确认每行数据对应的是“哪一年、哪个站点、什么生育期”。农学记录里最常见的翻车现场是站点改名导致同一块田被当成两个站点或者某年记录里的产量单位从公斤/亩变成了公斤/公顷数值直接差一个数量级。清洗的第一步是把这些单位统一然后按“站点 年份”做主键检查是否有重复行。import pandas as pd # 原始气象记录假设有 spreadsheet 风格的长表 weather pd.read_csv(weather_daily.csv) weather[date] pd.to_datetime(weather[date]) weather[year] weather[date].dt.year # 站点统一老站点代码替换成新代码 weather[station] weather[station].replace({A001_old: A001, A001_new: A001}) # 按站点和年份取出生育期划分信息 crop_calendar pd.read_csv(crop_calendar.csv) # 每个站点每年的播种/抽穗/收获日期 merged pd.merge(weather, crop_calendar, on[station, year], howinner) # 给每条日记录打上生育期窗口标签 def assign_window(row): if row[date] row[sowing_date]: return pre elif row[date] row[heading_date]: return window1 elif row[date] row[harvest_date]: return window2 else: return post merged[window] merged.apply(assign_window, axis1)这段代码的核心逻辑是给每天的天气记录打上窗口标签window1、window2分别对应营养生长期和生殖生长到灌浆期。这里故意只分了两个主要窗口因为如果计算条件再细代码可读性会下降。实际操作时你的窗口定义要跟作物生理阶段严格对齐。清洗阶段建议顺手做一个校验检查每个窗口内的记录天数是否在合理范围内比如window1明显少于40天多半是物候期数据有缺失。数据清洗完成后进入聚合步骤这是整个流程里最烦但最值得做扎实的一步。# 按站点、年份、窗口做聚合 agg_dict { temp_avg: mean, temp_max: mean, temp_min: mean, precip: sum, sunshine: sum, } feature_panel ( merged.groupby([station, year, window])[temp_avg, temp_max, temp_min, precip, sunshine] .agg(agg_dict) .unstack(level2) ) feature_panel.columns [ _.join(col).strip() for col in feature_panel.columns.values ] feature_panel feature_panel.reset_index()unstack(level2)会把窗口维度展开成列生成类似temp_avg_window1、rain_sum_window2的结构。这是长表转宽表的标准操作后续合并产量数据时一行就是一个样本。注意agg_dict里的sum和mean要跟字段语义匹配降水用累计、温度用平均搞反了模型精度会莫名其妙掉一截。聚合完成后把yield_data按站点 年份合并进来再删除pre和post窗口的列或者保留作为生育期外的气候背景你有两个选择但建议第一版先删掉保持特征集精简。3.2 随机森林回归训练代码从fit到R2的完整流程特征面板准备好之后训练代码本身反而很短。下面这份代码可以直接存成train.py跑起来。假设你已经把产量数据合并进了feature_panel目标列叫yield_kg_mu。import pandas as pd from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error import numpy as np # 读入清洗好的特征面板 df pd.read_csv(feature_panel_yield.csv) df df.dropna(subset[yield_kg_mu]) # 特征列与目标列分离 feature_cols [c for c in df.columns if c not in [station, year, yield_kg_mu]] X df[feature_cols] y df[yield_kg_mu] # 随机划分做初步验证仅适合先看模型有没有跑通 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) # 随机森林回归模型先用手感参数跑通 model RandomForestRegressor( n_estimators500, max_depthNone, min_samples_leaf2, max_featuressqrt, random_state42, n_jobs-1, ) model.fit(X_train, y_train) # 预测与评估 y_pred model.predict(X_test) r2 r2_score(y_test, y_pred) mae mean_absolute_error(y_test, y_pred) rmse np.sqrt(mean_squared_error(y_test, y_pred)) print(fR2 {r2:.3f}) print(fMAE {mae:.2f} kg/亩) print(fRMSE {rmse:.2f} kg/亩)几个参数值得单独说。n_estimators500在几百条样本的产量预测场景下足够收敛再多只会增加训练时间对精度几乎没有提升此时的训练集R2会十分接近1这是正常现象不要当模型真实能力来看。max_depthNone让树自由生长全靠后面的min_samples_leaf2控制过拟合这是随机森林的经典组合。max_featuressqrt在回归任务里表现稳定它迫使每棵树分裂时只随机看一部分特征增加树的多样性。n_jobs-1让所有CPU核一起干活样本量小的时候训练就几秒钟的事没必要省。如果你机器上的Python环境还没配好IDE用VSCode或PyCharm都行先照着官方步骤把Python装好再给解释器装上pandas、scikit-learn、numpy这几个包这段代码就能直接运行。第一次跑如果报ModuleNotFoundError基本就是缺包用pip install补上即可。3.3 保存与加载模型训练一次后面直接用产量预测的实际使用场景是“模型训练一次每个关键节点预测多次”。因此训练完一定要把模型落盘。joblib比pickle更适合大对象加载速度也更快。import joblib # 保存训练好的模型和特征列名 joblib.dump(model, rice_yield_rf.joblib) joblib.dump(feature_cols, feature_cols.joblib) # 新一年预测时 new_year_features pd.DataFrame( [ { temp_avg_window1: 24.5, rain_sum_window1: 180.0, # ... 所有特征列都要有顺序不要求一致 } ] ) # 加载模型与特征列按列名对齐 loaded_model joblib.load(rice_yield_rf.joblib) loaded_cols joblib.load(feature_cols.joblib) new_year_features new_year_features[loaded_cols] pred loaded_model.predict(new_year_features) print(f预测产量: {pred[0]:.1f} kg/亩)加载模型时最容易犯的错是特征对齐问题训练时有22列预测时只喂了18列模型会直接报错。保存feature_cols并强制预测数据按这个顺序排就是为了从根源上避免这个问题。我一般还会把模型版本和训练时间一起写进文件名比如rice_yield_rf_20240601.joblib这样后来的人拿到模型知道是哪个版本训练出来的不会出现“训练了个寂寞”的情况。4. 随机森林三个关键参数与交叉验证别让默认参数拖累你的预测精度4.1 n_estimators、max_depth、min_samples_leaf到底怎么调随机森林的默认参数对分类任务很友好但回归场景尤其是小样本的农学数据默认参数往往不是最优解。训练时最值得关注的参数就三个n_estimators、max_depth、min_samples_leaf。n_estimators是树的棵树。产量预测这种几百条样本的任务从100棵看到1000棵测试集误差通常在300棵附近就进入平台期。判断方法很简单训练完成后画一条“测试集误差随n_estimators变化”的曲线如果曲线在500之后还在明显下降说明还有增益空间否则就停在当前值。不要盲目追求几千棵树徒增预测时的计算量。max_depthNone让树充分生长的时候控制过拟合的任务落到了min_samples_leaf身上。这个参数的意思是叶子节点最少要有几个样本。设成1时拟合能力最强但方差很大设成5、10时模型更平滑但可能欠拟合。小样本产量数据里我一般从2开始试配合交叉验证往4、6方向探索。有一种常见误用是反着来把max_depth设成3、5来限制树深结果模型欠拟合测试集R2稳定在0.2以下。随机森林不是GBDT不要用限制max_depth的思路来控制过拟合这是在用调GBDT的习惯调随机森林效果很别扭。max_features控制每棵树分裂时随机抽取的特征数。回归任务用sqrt是公认的默认选择但如果你发现特征间高度相关可以试试0.3、0.5这种比例值。特征特别多时调低它能增加树的多样性。参数对模型的影响要放在一起看不能单独调。下面这张参数速查表是给新手抄作业用的参数常见取值范围对模型的影响产量预测场景建议n_estimators1001000越大越稳定但边际收益递减500起步看误差曲线再增减max_depthNone或1030None时靠叶子约束防过拟合默认None不要主动限深min_samples_leaf110越大越平滑越小越容易过拟合从2开始结合CV调max_featuressqrt/0.30.5越小树的多样性越高默认sqrt可试0.5random_state任意整数固定后结果可复现固定为42或2024否则没法对比4.2 用GridSearchCV找参一份可直接改的调参代码手感参数只适合跑通流程想要一份有说服力的精度报告交叉验证是必须的。产量预测中样本量不大5折交叉验证足够既能评估模型稳定性又不会因为折数太多导致每折训练数据太少。from sklearn.model_selection import GridSearchCV, KFold # 参数搜索空间先粗后细 param_grid { n_estimators: [300, 500, 800], min_samples_leaf: [2, 4, 6], max_features: [0.3, 0.5, sqrt], } # 5折交叉验证R2作为评分指标 kfold KFold(n_splits5, shuffleTrue, random_state42) search GridSearchCV( estimatorRandomForestRegressor( max_depthNone, random_state42, n_jobs-1, ), param_gridparam_grid, scoringr2, cvkfold, refitTrue, verbose1, ) search.fit(X, y) print(f最优参数: {search.best_params_}) print(f最优交叉验证R2 {search.best_score_:.3f}) print(f最优模型测试集表现: {search.best_estimator_})refitTrue表示找到最优参数后用全部训练数据重新训练一份模型存到best_estimator_里省去手动再fit一次。scoringr2代表交叉验证里每一折都算R2然后取平均如果你的任务更关注绝对误差也可以改成neg_mean_absolute_error。网格搜索在参数组合多的时候会比较慢一般先用大间隔粗搜一遍确定范围比如min_samples_leaf先试[2, 5, 10]锁定最优区间之后再细搜[2, 3, 4]。这一步能省下大量不必要的训练时间。看交叉验证结果时重点看best_score_和单折之间的方差。如果5折的R2分别是0.71、0.68、0.73、0.69、0.70说明模型稳定这个结果可以往外报如果某折R2跑到0.9另一折只有0.2那大概率不是参数问题而是数据划分里有泄漏或者某一年的气候极端异常。这时候先不要调参回头查数据。5. 随机森林产量预测避坑手册数据泄漏、过拟合与站点外推翻车记录5.1 随机划分导致结果虚高跨年验证立刻现原形现象用train_test_split随机打乱数据测试集R2达到0.85模型看起来完美。但把模型按年份做前向验证——用2010到2019年训练预测2020到2022年——R2直接掉到0.3以下。原因同一站点不同年份的气象特征高度相似随机划分时同一个站点的数据同时出现在训练集和测试集模型等于“见过”这个站点的产量水平测试成绩有水分。跨年验证才是产量预测的真实场景预测的是未来不是猜测历史里某一年。解决评估时必须按年份切分保证测试集的年份晚于训练集。train_test_split只用来做流程冒烟测试最终结论以跨年验证为准。代码如下train_df df[df[year] 2019] test_df df[df[year] 2020] model.fit(train_df[feature_cols], train_df[yield_kg_mu]) y_pred model.predict(test_df[feature_cols]) r2 r2_score(test_df[yield_kg_mu], y_pred)5.2 调参时反复看测试集测试集变成了训练集现象网格搜索跑完之后感觉R2还差点意思于是改了参数空间再搜一次看到测试集R2从0.62涨到0.68心想终于调通了。原因每次看测试集结果再回头改参数测试集的信息实际已经参与进了你的决策过程。多来几轮测试集就被“记住”了最终的精度报告严重失真。小样本场景下这个问题尤其严重因为随机森林在这些数据上很容易做到表面上的高拟合。解决把数据切成三份——训练集、验证集、测试集或者更简单地固定一个你绝不看的“最终评估集”。调参只用训练集配合交叉验证全部调完之后才碰最终评估集一次得到的就是可以写进报告的精度。如果感觉“再看一眼”也没关系请记住这份报告将来要拿去跟农学专家或领导对齐虚高0.05的R2在真实业务里立刻会被戳穿。5.3 全生育期气象特征做预测收获季节才能算出来提前量为零现象把所有气象窗口的特征算完模型精度0.72看起来不错。但等到收获后再预测当年产量预测出来也没有业务意义了。原因有些产量预测项目实际要在幼穗分化期甚至分蘖期就给一个大致估计指导后续施肥和灌溉。全生育期的特征在收获前根本取不到。解决在预测任务定义阶段就明确落地时间点。如果要在7月20日预测当年产量就用7月20日之前能取到的特征训练一个“早期预测模型”在收获后才做估产才用全生育期特征。两个模型的精度不能横向比较因为业务价值完全不同。同样的代码一个用截断窗口特征一个用完整窗口特征分别训练、分别报告。5.4 站点外推时模型翻车换了新站完全失灵现象本省训练好的模型拿到隔壁县用R2直接变成负数预测值全部压在一个很窄的区间里平均值都回不到实际水平。原因随机森林只能内插不能外推。产量跟气候的关系在不同区域可能完全不同模型如果没见过目标区域的站点数据就不会知道那里的地理特征跟产量的关系。解决新区域必须至少采集该区域近三年的历史数据做微调或重训。此外检查特征分布是否有明显差异隔壁县海拔高、积温低这些量在特征空间里超出了训练集的范围模型预测自然回到均值附近。做区域推广前先算一下新站点特征和训练集特征的距离分布偏移太远就直接放弃迁移重新攒数据。5.5 特征重要性被高基数类别变量绑架现象加了站点的经纬度、海拔之后特征重要性排名前两位都是经纬度相关特征气象变量全部排到后面跟农学常识冲突。原因地理位置特征和产量之间的关系太直接了——同一块田产量就是更好。但如果站点数量少模型很容易把“地理位置”当成划分高产低产的简单标签来用从而不再去细究气象特征的作用。解决先单独跑一个只含气象和管理特征的模型看特征重要性的业务合理性再逐步加入位置特征。位置特征重要本来就合理但别让它完全压制农学变量。如果连灌浆期温度的重要性都排不进前五大概率是某些站点标记错误或产量数据有单位不一致问题回到数据清洗那一步再查。6. 用特征重要性指导下一次迭代让产量预测从黑匣子变成可用结论模型训完不是终点你还需要回答“影响产量的关键因素到底是什么”。随机森林的特征重要性可以给出第一个答案但直接打印feature_importances_往往不够直观因为它的数值绝对值没有太多业务含义。我一般的做法是先输出排名前十的特征再画一张水平柱状图筛选出关键变量后按这些变量的分组统计产量均值验证模型给出的结论是否符合实际农学认知。更进一步的验证方法是部分依赖图它能展示单一特征变化时预测产量的平均响应。比如想看灌浆期平均温度从22度升到28度时预测产量怎么变用sklearn.inspection.partial_dependence可以快速画出来。这一步对和农学专家沟通非常有帮助——你拿着图去问“这个曲线符不符合你的经验”对方能直接给你下一轮特征优化的建议而不是对着一个黑匣子模型干瞪眼。产量预测的模型迭代从来不是无脑加数据。每次迭代都要回到业务本身问三个问题这次预测是要在哪个时间点给出结果地理范围有没有扩大有没有新的管理措施数据能补进来数据决定模型上限模型只是把数据里的信号提炼出来。我自己的习惯是每训练一版模型就顺手把特征重要性和跨年验证的R2记在一个备忘文档里隔几个月回头翻能清楚看到哪个特征一直有效、哪个特征只在特定年份重要。这套流程走下来比调一天参数有用得多。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。