
简介围绕2024年高教社杯全国大学生数学建模竞赛C题本份资源提供一套完整的农作种植策略可视化代码面向参赛学生、建模爱好者以及需要完成数据可视化分析的研究者。压缩包内含31个文件整体大小约2MB其中6个Python脚本覆盖数据预处理、描述性统计、异常值分析、柱状图与散点图绘制等关键步骤20张PNG图片展示地块面积分布、销售单价与亩产量关系、相关性热图、箱线图、QQ图等核心分析结果5个Excel文件包含原始附件及清洗整理后的数据方便直接对照复现。已有1005人学习下载适合备赛期快速上手。资源以“数据清洗—指标分析—可视化输出”为主线帮助读者理解农作物种植策略中的产量、价格、成本与面积等多维指标关联掌握用matplotlib等工具将模型结果转化为直观图表的方法可直接用于论文配图或模型效果展示有效节省从零编写代码的时间。 2024年高教社杯数模竞赛C题出来那天我看群里不少队伍第一反应是“这题怎么这么长”满屏的作物名称、地块编号、预期销量区间光是读题就花了一个多小时。但等我自己把数据拉进Python、把几组关键图表画出来之后才意识到这道题真正的难点不在题面长而在于它把“不确定性”藏在了每一张表格里。这篇东西就是我做完C题可视化部分后的一份完整复盘包含从数据结构梳理、图表选型到核心绘图代码、以及从图里反推建模方向的全部思路希望能帮到正在备赛或者打算用Python做竞赛可视化的同学。C题的种植策略本质上是一个多地块、多作物、多年份的资源配置优化问题题目给的数据不是传统意义上的“确定值”更多是以预期区间形式出现的销量、成本和价格。这就意味着你用表格逐行看数据时很难直观感受到“哪种作物在哪种地块上更值得种”“市场波动对方案冲击有多大”但一旦换成合适的图很多结论几乎是自己跳出来的。接下来我按当时实际操作的顺序把这套可视化方案从头到尾拆开讲。1. C题到底在考什么先给2024年的种植数据算一笔明白账1.1 题面信息的基本盘先捋一下C题给的信息形态。题目围绕某乡村的农作物种植展开核心数据大概分几类一是地块信息包括不同地块的面积、所属村组、地块类型二是作物信息包括作物名称、种植成本、亩产量、销售价格、预期销售量三是时间维度覆盖2024到2030年并且很多关键参数是以“区间”形式给出的。这个“区间”是C题和我以前做过的很多优化题最不一样的地方。往年不少题目给出的价格、销量都是一个确定数你按确定参数建模就行但这道题里预期销售量可能是一个波动范围价格也未必是固定值。你在建模时首先要回答的问题就是我到底按区间的哪个值来算收益是保守取下界、乐观取上界还是做情景加权可视化此时的作用就是把这种不确定性摊开在你们面前而不是让它藏在表格深处。1.2 从任务反推核心变量C题通常会有多个问题我当时是把任务拆成三层来理解的。第一层给定未来几年的基本数据不考虑额外复杂约束制定一个最优种植方案目标基本是“收益最大化”约束包括地块面积、作物适宜性、市场需求上限等。第二层会加入轮作或重茬约束比如豆类作物不能连作、某些作物需要间隔一定年份才能再次种植这会让问题从“单年优化”升级成“多年份联动的排程问题”。第三层引入智慧大棚等新条件相当于把一部分地块的种植能力做了升级成本变了、可种作物范围变了方案也要随之调整。因此这道题真正要你们回答的其实是三件事种什么、种在哪、种多少。所有可视化和建模工作都是围绕这三个问题展开的。你在做图之前最好先把这三个问题写在一张纸上不然很容易画出一些“好看但没用”的图。1.3 为什么可视化在这道题里是明确的加分项我见过不少队伍论文里放了三张柱状图就交上去了。但在C题这种信息量很大的题目里图表的角色远不止“证明你做了数据分析”它其实是你的推理链条。评委看论文的时间非常有限与其让他们在密密麻麻的表格里找你“为什么选这个方案”不如直接用图把“我和方案之间的因果关系”呈现出来。具体到C题至少有三类图是值得做的展示作物间经济效益差异的对比图、展示未来几年市场不确定性的区间图、展示最终种植方案在时间和地块两个维度上分布的图。如果这三类图做好了整篇论文的骨架就立住了。2. 可视化方案的设计思路先想清楚每张图要替你说什么2.1 图的本质是证据链不是装饰很多同学做可视化有个误区先不管数据长什么样打开matplotlib就是一顿炫技最后画了一堆3D曲面图、桑基图结果评委根本看不明白。我做竞赛图的第一个原则是每张图都必须能回答一个具体问题。C题里我觉得值得回答的问题包括哪些作物亩均收益高哪些作物虽然单价高但产量低哪些地块适合种什么未来销量区间变化对方案影响大吗轮作约束下同一块地在年份间的种植安排是否合理这一串问题列出来图的选型基本就定了而不是反过来。2.2 图表的四类角色分工以我当时C题的可视化方案为例图表大体分四类。第一类是经济效益对比图用来展示不同作物的亩产量、成本、价格、亩均利润。这类图解决的是“种什么”的问题是所有后续建模的基础输入。第二类是市场预期区间图把2024到2030年每种作物的预期销量和价格区间用区间带画出来。它解决的是“市场到底有多不确定”的问题。第三类是方案结果图把模型算出来的最优种植方案投射到地块和年份的矩阵上用热力图或者堆叠图呈现。第四类是约束检查图专门画一个“轮作序列”看同一块地上连续年份种了什么作物一眼就能发现有没有违规连作。这样划分之后整个可视化的叙事逻辑就很清楚了先看基础数据再看市场环境然后看方案生成最后验证方案的可行性。你论文里的图表顺序也完全可以按这条线走。2.3 配色、布局和标注的取舍原则竞赛图表和平时做数据分析的图表有个重要区别评审场景是纸质阅读和时间有限的观看。因此配色要尽量用同一色系或少量强调色不要用彩虹色字号要偏大坐标轴标题要写完整图例位置要固定且不遮挡数据。更关键的是每一张图都要有一个“一眼能看出的结论”如果一张图看了十秒还不知道想表达什么那这张图就应该重画。我一般会在图旁边直接加一个文本框写上一句类似“2024-2030年豆类轮作约束下地块A的种植序列无连作违规”的结论。别觉得这么做多余——对评委来说这比让他在图里自己找结论要友好太多。3. 核心可视化代码拆解从数据表格到成图的完整路径3.1 数据读取与口径统一先说我当时处理数据的方式。C题附件往往是多张Excel表包含作物成本、销售数据、地块信息等。为了方便可视化我第一步是把所有表按“地块编号年份作物名称”作为主键整理成一张长表列结构大致如下。import pandas as pd import numpy as np # 示意假设已经将题目附件整理为长表 clean_data.csv # 列说明year年份、plot_id地块编号、crop作物名称、area亩数、 # yield_per_mu亩产量(斤/亩)、cost_per_mu种植成本(元/亩)、 # price_per_kg销售单价(元/斤)、sales_low销量下界(斤)、sales_high销量上界(斤) df pd.read_csv(clean_data.csv, encodinggbk) print(df.head()) print(df.dtypes)需要注意题目里有的字段单位可能是“吨”“公斤”有的可能是“斤”这就涉及单位统一问题。我当时把产量和销量统一换算成“斤”把价格统一成“元/斤”成本统一成“元/亩”避免后面算收益时出现数量级错误。数据量不大的情况下用pandas做这种清洗很快但单位坑一旦踩中后面所有图都会跟着错。3.2 作物经济效益对比图用柱状图直接锁定赢家在“种什么”这个问题上我当时画的第一张核心图是“亩均利润对比”。计算逻辑很简单亩均收入 亩产量 × 单价亩均利润 亩均收入 - 种植成本。需要注意这里的“亩均收入”用的是题目给的销售价格不是市场实时价格。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # 处理中文显示 plt.rcParams[axes.unicode_minus] False # 按作物汇总平均数据 crop_stats df.groupby(crop).agg( yield_per_mu(yield_per_mu, mean), cost_per_mu(cost_per_mu, mean), price_per_kg(price_per_kg, mean) ).reset_index() crop_stats[profit_per_mu] crop_stats[yield_per_mu] * crop_stats[price_per_kg] - crop_stats[cost_per_mu] crop_stats crop_stats.sort_values(profit_per_mu, ascendingTrue) # 横向条形图方便看清作物名称 fig, ax plt.subplots(figsize(10, 8)) bars ax.barh(crop_stats[crop], crop_stats[profit_per_mu], color#4C72B0) ax.set_xlabel(亩均利润元/亩) ax.set_title(各作物亩均利润对比2024-2030平均) # 在条形末端标数值 for bar, val in zip(bars, crop_stats[profit_per_mu]): ax.text(val 5, bar.get_y() bar.get_height()/2, f{val:.0f}, vacenter, fontsize9) plt.tight_layout() plt.savefig(profit_per_mu.png, dpi300) plt.show()这张图画出来之后我第一反应是“果然高价值蔬菜类作物的亩均利润明显高于普通粮食作物”。但这里要特别提醒一个问题亩均利润高的作物未必应该无限扩种因为题目里还有预期销量上限。你画完图一定要再问自己一句高利润作物的销量天花板在哪里如果市场只需要那么多多种出来的部分怎么处理这个问题是后面建模的核心也是C题最容易区分队伍层次的地方。3.3 预期销量区间图把不确定性“画”出来C题给出的预期销量往往不是一个单点而是一个区间。我当时把每种作物的销量下界和上界分别取出来用折线加填充带的方式画出来。这样不仅能看到变化趋势还能直观看到“不确定性有多大”。# 示例以某一作物为例画2024-2030年预期销量区间带 crop_name 西红柿 # 替换为目标作物 crop_df df[df[crop] crop_name].groupby(year).agg( sales_low(sales_low, mean), sales_high(sales_high, mean) ).reset_index() fig, ax plt.subplots(figsize(10, 6)) ax.plot(crop_df[year], crop_df[sales_low], label销量下界, color#C44E52) ax.plot(crop_df[year], crop_df[sales_high], label销量上界, color#55A868) ax.fill_between(crop_df[year], crop_df[sales_low], crop_df[sales_high], color#C44E52, alpha0.2, label预期区间) ax.set_xlabel(年份) ax.set_ylabel(预期销量斤) ax.set_title(f{crop_name} 2024-2030年预期销量区间) ax.legend() plt.tight_layout() plt.savefig(sales_range.png, dpi300) plt.show()从这张图里能明显读出两件事。第一某些作物的预期销量区间特别宽说明市场不确定性大建模时不能把销量当成一个固定常数否则方案很容易被“过度乐观”或“过度保守”带偏。第二不同作物的区间宽窄差异可以作为风险度量的一个参考区间越宽意味着最终收益的波动可能越大。我当时在论文里就把“区间宽度”处理成了一个风险指标在目标函数里加入了对波动性的惩罚这样算出来的方案比单纯把销量取下界要合理得多。3.4 方案结果热力图让评委一眼看懂你种了什么模型跑完之后最需要展示的是结果方案。C题的结果是一个高维组合常见做法是画“地块-年份”热力图颜色代表不同作物。这样一张图就能说清楚每一块地在每一年到底种了什么整体轮作关系是否清晰。# 假设 solution_df 是模型输出的方案表 # 列plot_id、year、crop、area solution_df pd.read_csv(solution.csv, encodinggbk) # 将作物名转为类别编码 solution_df[crop_code] solution_df[crop].astype(category).cat.codes pivot solution_df.pivot_table(indexplot_id, columnsyear, valuescrop_code, aggfuncsum) # 用imshow画热力图 fig, ax plt.subplots(figsize(12, 8)) im ax.imshow(pivot.values, cmaptab20, aspectauto) ax.set_xticks(range(len(pivot.columns))) ax.set_xticklabels(pivot.columns) ax.set_yticks(range(len(pivot.index))) ax.set_yticklabels(pivot.index) ax.set_xlabel(年份) ax.set_ylabel(地块编号) ax.set_title(最优种植方案地块×年份 作物分布热力图) # 图例显示作物类别 crop_names solution_df[[crop_code, crop]].drop_duplicates().sort_values(crop_code)[crop].tolist() cbar plt.colorbar(im, ticksrange(len(crop_names))) cbar.ax.set_yticklabels(crop_names) plt.tight_layout() plt.savefig(planting_heatmap.png, dpi300) plt.show()这里有个细节我踩过坑当方案里作物数量比较多时直接用作物名作为色块标签图例会非常拥挤颜色也容易混淆。我的解决办法是先按作物大类分组比如“粮食作物”“豆类作物”“蔬菜类作物”“果类作物”然后每个大类给一个主色调同一大类下的不同作物用深浅区分。这样整张图既不会信息过载又能看出轮作大类之间的交替关系。3.5 轮作约束检查图把连作风险标出来C题的轮作约束是第二问以后的重头戏。比如豆类作物不能连续在同一地块种植或者某类作物种植后需要间隔几年才能再种。手工检查这种约束非常痛苦尤其是几十个地块、七年时间手算基本不可能。我当时的方法是直接写一个“违规标记图”对每个地块逐年扫描种植序列如果发现同一作物连续种植超过允许年份就在对应位置打一个醒目的红色标记。# 示例检查每一地块上“豆类作物是否连续种植两年以上” legume_set {大豆, 绿豆, 红豆, 花生} # 按题目要求调整 # 构建地块-年份-作物的透视表 crop_pivot solution_df.pivot_table(indexplot_id, columnsyear, valuescrop, aggfunclast) violations [] for plot_id in crop_pivot.index: series crop_pivot.loc[plot_id] for year in series.index[:-1]: if series[year] in legume_set and series[year 1] in legume_set: violations.append((plot_id, year, year 1)) print(连作违规记录, violations) # 如果违规过多可以在热力图上叠加红色网格标记图上标红之后你不需要再去论文里用大段文字描述“我们验证了轮作约束满足”直接把这张图放上去结论一目了然。哪怕模型结果确实违规了这张图也能帮你在交卷前尽早发现逻辑漏洞比模型跑完就万事大吉要稳妥得多。4. 图表背后的建模启示怎么从图中找到优化方向4.1 高效益≠大面积扩种市场天花板才是隐形约束把作物经济效益对比图画出来之后不少队伍会掉进一个陷阱既然西红柿、草莓这些作物亩均利润高那就大面积种它们。但你一旦叠加销量区间图就会发现高效益作物的预期销量区间往往很小市场根本消化不了那么多产能。这时候你会意识到C题的约束重点不是“地块不够”而是“市场吃不下”。从建模角度我的处理方法是把目标函数拆成“种植收益 - 未售出损耗 - 风险惩罚”。对于销量上限不再简单写成“产量≤销量”这个硬约束而是引入一个可调参数允许在特定情况下超产但超产部分按低价或废弃处理。这样模型更有弹性也更能体现题目里“预期”二字的含义。4.2 区间宽度给敏感性分析提供了天然坐标销量区间带图画完之后还可以进一步做“分作物敏感性分析”。我把每种作物按区间宽度排序区间最宽的几类作物挑出来单独测试价格上下浮动10%、销量上下浮动20%时最优方案和最终收益的变化幅度。结果发现方案对某些高价蔬菜的销量波动非常敏感而对粮食作物相对不敏感。这个结论放在论文里很加分因为它证明了你们不只是“跑出了一个方案”还想清楚了方案在什么情况下会失效、失效的程度有多大。这些分析全都可以从区间带图上延伸出来不需要额外找数据。4.3 热力图还能帮你发现“组合拳”式的种植规律种植方案热力图除了展示结果还有一个隐含价值它可以帮你做模式识别。比如你看图发现某一类地块连续几年都在“粮食作物-豆类作物”之间交替说明模型倾向于用豆类来养地另一个地块则长期种蔬菜说明那块地的自然条件和灌溉条件更适合高附加值作物。这种规律在表格里很难发现但在热力图上几乎是自动呈现的你可以把它作为论文里“方案合理性的进一步讨论”素材。5. 做图过程中踩过的坑与经验总结5.1 中文字体问题一套组合拳解决matplotlib默认字体是不支持中文的直接用plt.title写中文输出就是一个个方框。解决方法是设置中文字体比如SimHei、Microsoft YaHei同时要关闭unicode负号否则坐标轴上的负号会显示异常。如果你在服务器或者云端环境跑可能还需要手动指定字体文件路径。from matplotlib import font_manager import matplotlib.pyplot as plt # 方式一直接指定系统已安装的中文字体 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False # 方式二如果上面不生效可以直接加载字体文件 # font_path /usr/share/fonts/msyh.ttf # font_prop font_manager.FontProperties(fnamefont_path) # 然后在每个标题里统一传 fontpropertiesfont_prop这个问题越早解决越好不然画到中途才发现所有图的标题都是乱码重新生成一遍非常浪费时间。5.2 区间数据画图时容易把上下界搞反画销量区间带时我一开始直接用sales_low和sales_high画了两条线结果fill_between的上界传成了sales_low、下界传成了sales_high整张图看起来像一个倒扣的碗差点把结论带偏。建议在画任何带区间的图时先打印一下最大值和最小值确认数据范围合理后再绘图。5.3 堆叠面积图看比例很爽看总量很坑有段时间我想用堆叠面积图展示每年各类作物的种植面积结构变化一开始觉得挺好看。但后来发现堆叠图的“中间层的绝对高度变化”非常有误导性——某类作物面积没变但因为它下面那层面积变了它在图上就会看起来忽高忽低。后面我果断放弃堆叠图改用100%百分比堆叠图或者分面的小多图因果更清晰。5.4 不要为画图而画图先有结论再选图这是我每次带队都反复强调的一点。C题信息量大能画的图太多了但你最终放上论文的图应该控制在8到12张之间。每张图必须有明确的定位要么是输入数据的洞察要么是模型结果的展示要么是约束满足的验证。画图之前先问自己一句“这张图我要让评委看到什么结论”如果回答不上来就不要画。最后再分享一个个人经验可视化从来不是建模竞赛的附属品它其实是建模思路的探照灯。2024年C题这套数据我可以说一大半的建模决策都是从图里看出来的——哪几种作物是利润引擎哪些市场区间宽得吓人轮作约束切在哪个年份会让方案结构变化最大。与其对着表格冥思苦想不如先把该画的图都画出来让数据自己开口说话。这也正是我写这篇复盘最想传达的东西。本文还有配套的精品资源点击获取