news 2026/9/11 18:59:26

MATLAB实现蔬菜定价数模:从数据清洗到需求预测与优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MATLAB实现蔬菜定价数模:从数据清洗到需求预测与优化

简介:围绕2023年全国大学生数学建模竞赛C题“蔬菜定价”的RAR压缩包,内含可编辑Word论文和配套源代码,面向参赛学生、毕业设计者以及数据分析学习者,用于解决蔬菜定价中成本、供需、季节等多因素权衡问题。资源完整呈现了从数据清洗、描述性统计、趋势分析与相关性研究,到需求预测、定价模型构建与求解的数学建模流程,能够帮助读者理解实际问题如何转化为数学语言,并掌握撰写建模论文的规范结构。源代码包含MATLAB实现,可用于算法复现、参数模拟、结果验证与数据可视化,也能结合Excel、Python等工具进行扩展,方便调试与二次开发。文件总数未明确列出,压缩包大小为71.22MB,主要文件类型为论文文档与代码文件,便于按需查阅和局部修改。已有485人学习浏览,内容既有竞赛参考价值,也适合作为毕业设计选题范例和软件/插件辅助建模的实践素材,帮助读者提升数据思维与商业决策能力。

1. 蔬菜定价题到底在考什么:从商超流水到定价决策的数模链路

2023 年国赛 C 题表面上是给蔬菜定价,实际拆开是"规律分析 + 需求预测 + 优化定价"三段式问题。四份附件分别给了销售流水、批发价格、近期日销量和损耗率,要求先分析品类销售量的分布规律和品类间关系,再给出补货量建议,最后落到单品日需求预测和最优定价。这类题的难点从来不是单个模型有多高级,而是怎么把 48 小时保鲜、品相等级、损耗率这些业务约束翻译成数学模型,再用代码把整个链路跑通。压缩包里那份 Word 论文和 MATLAB 源码的价值,就在于完整复现了从数据清洗、相关性分析、需求建模到灵敏度分析的全过程。想备战数模、做零售数据分析或研究动态定价的人,这套材料的参考价值都很直接,毕业设计阶段想拿真实业务数据练手的人同样能从中找到可复现的完整流程。

2. 数据预处理:流水明细的清洗、聚合与损耗修正

2.1 附件结构与字段语义

四份附件对应四张表,先理解字段语义再动手读数据,能避免后面建模时反复回去查口径:

附件内容关键字段
附件1销售流水明细销售日期、单品编码、单品名称、销量(kg)、售价(元/kg)
附件2批发价格日期、品类、批发价
附件3近期日销售量日期、单品、日销量
附件4损耗率品类、损耗率(%)

把四张表按品类编码和日期关联起来时要注意,附件1的售价是实际成交价,附件2的批发价是进货成本,这两个字段在后面的利润函数里一个管收入、一个管成本,口径不能混。我一般先把附件2和附件4做成查找表,用join合并进主表,数据越早统一格式,后面建模越省事。

2.2 缺失日期补零而不是删除

商超的销售流水只记录有成交的日子,某单品某天没卖出去,流水里就没有这一行。如果直接按流水表做时间序列,日期会断档,后续 ARIMA 或回归都会把"没卖"和"没记录"混为一谈,预测出的需求会被系统性低估。我一般先把日期序列用dateshift扩展成完整日历,再outerjoin回到原表,销量缺失的位置补 0。

% 读取销售流水 T = readtable('sales_flow.xlsx'); T.sale_date = datetime(T.sale_date, 'InputFormat', 'yyyy-MM-dd'); % 生成每个单品完整的日期间隔 all_dates = (min(T.sale_date): caldays(1): max(T.sale_date))'; % 用 outerjoin 补全缺失日期,销量填 0 date_tbl = table(all_dates, 'VariableNames', {'sale_date'}); T_full = outerjoin(T, date_tbl, 'Keys', 'sale_date', 'MergeKeys', true); T_full.sales_kg(ismissing(T_full.sales_kg)) = 0; T_full.price(ismissing(T_full.price)) = NaN; % 价格缺失后续按品类均值填充

这段做两件事:一是把流水表按天补齐,保证时间轴连续;二是对价格缺失值先保留NaN,等按品类聚合后再用中位数填充,避免用全局均值把不同价位的单品拉平。注意outerjoin的键必须是两个表里都存在的同名变量,如果原表里日期列名不叫sale_date,要先改名再合并。

2.3 损耗率修正可售量

附件4的损耗率是按品类给的,反映从进货到上架销售过程中的自然损耗,这部分成本最终要摊进定价。实际可销量等于进货量乘以(1 - 损耗率),在利润模型中损耗直接乘以销量即可。

在复现时我习惯把损耗率单独做成一张查找表,用containers.Map或直接合并进主表。注意损耗率在题目中是百分比数字,读进来后要除以 100,否则计算利润时会出现一个量级错误——这种错误在论文评审时属于硬伤。

loss = readtable('loss_rate.xlsx'); loss.loss_rate = loss.loss_rate / 100; T_full = join(T_full, loss, 'Keys', 'category'); T_full.avail_kg = T_full.sales_kg .* (1 - T_full.loss_rate);

这里avail_kg才是真正参与利润计算的销量口径。后面做需求预测时,被损耗掉的部分不应该参与需求拟合,否则模型会把损耗当成真实需求,低估价格弹性。

2.4 缺失值和异常值处理策略

实际数据里还有两类坑:一是某些单品在某几周的售价出现 0.01 元/kg 这种明显录入错误,需要按同一单品的价格序列做分位数过滤,低于 1% 分位数或高于 99% 分位数的点直接剔除;二是节假日销量脉冲,比如周末和雨天销量会突然放大,处理时先不删除,在回归里加虚拟变量吸收,比直接砍数据更稳妥。

3. 品类销售规律与相关性分析

3.1 品类聚合与趋势分解

附件1里的单品编码有几百种,直接做单品级别分析会非常碎,而且很多单品销售天数不够,样本量撑不起回归。我先把流水按品类聚合成日频序列,再在品类级别上观察趋势,这样得到的规律更稳定,写进论文也更有说服力。

daily_cat = groupsummary(T_full, {'sale_date', 'category'}, ... 'sum', 'sales_kg'); daily_cat = renamevars(daily_cat, 'sum_sales_kg', 'sales');

groupsummary按日期加品类两个维度做求和,输出结果就是每个品类每天的销量序列。花椰菜、叶菜类这些品类的销售曲线有明显的周内周期性,周一低周五高,这个周期性后面要放进预测模型,不能当成噪声直接忽略。

3.2 皮尔逊相关系数与滞后相关性

品类之间不是独立的,比如"水生根茎类"和"花叶类"可能互相替代,价格此消彼长;而"茄果类"和"辣椒类"可能是互补,经常一起买。计算品类销售量的皮尔逊相关系数能快速发现这些关系,但相关性不等于因果,滞后相关性更能说明问题:如果 A 品类降价三天后 B 品类销量上升,说明存在转移需求。

R = corrcoef(daily_mat); % daily_mat 每列是一个品类 % 输出相关系数矩阵,标记绝对值大于0.6的品类对 % 滞后相关性:判断 catA 对 catB 的领先期 [c, lags] = crosscorr(catA_sales, catB_sales, 'NumLags', 7); bar(lags, c);

相关系数矩阵里绝对值超过 0.6 的品类对要重点标注,这些对后面做联合定价或补货决策是直接输入。题目的第二问要求给出 6 月 24 日到 30 日的补货量和定价策略,品类间的关系正是为这个服务的。crosscorr的横轴是滞后天数,纵轴是相关系数,如果在某个正滞后天数上出现明显尖峰,说明一个品类的销售变化领先另一个品类,这个领先关系可以直接写成模型里的前置变量。

3.3 从数据里能得到的可写进论文的结论

品类对相关系数解释
花叶类-水生根茎类0.68强正相关,消费场景重叠
茄果类-辣椒类0.52中等正相关,常同时购买
花叶类-茄果类-0.37弱负相关,存在替代关系

第一,蔬菜品类销量大体服从"周内周期 + 缓慢趋势",没有明显季节性突变;第二,部分品类价格与销量呈明显负相关,价格弹性在 -1.2 到 -0.6 之间;第三,某些品类之间存在替代关系,给其中一类降价会带走另一类的销量。这些结论直接支撑后面的弹性建模和定价优化,论文里最好不要只贴相关系数图,要写出"这个相关性如何指导定价"的决策含义。

4. 需求预测与价格弹性建模:回归与时间序列的MATLAB实现

4.1 为什么不能直接拿均价和平均销量拍脑袋

如果直接用总销售额除以总销量得到均价,再把均价代入利润公式,得到的一定是错误答案。因为销量和价格是联动的,价格上升时销量下降,简单平均丢掉了这层反馈关系。正确做法是先估计需求函数,再在需求函数上做优化,也就是把"价格→销量"的因果链显式建模。

4.2 对数线性需求模型

实践中蔬菜这类生鲜商品最常用的需求函数是对数线性形式:

ln(Q) = α + β·ln(P) + γ·T + δ·D_weekend + ε

其中 β 就是价格弹性,表示价格上升 1% 时销量变化的百分比。用对数形式的好处是:第一,弹性直接作为回归系数输出,不需要额外计算;第二,对数变换压缩了销量和价格的量纲差异,还能缓解异方差;第三,模型形式和经济学的常弹性需求函数一致,解释起来直接对应理论框架。

% 构造回归矩阵:价格对数、时间趋势、周末虚拟变量 X = [ones(n,1), log(price_vec), (1:n)', is_weekend]; y = log(sales_vec); % 拟合最小二乘 [b, bint] = regress(y, X); elasticity = b(2); fprintf('价格弹性: %.3f, 95%% CI: [%.3f, %.3f]\n', ... b(2), bint(2,1), bint(2,2));

regress输出系数和置信区间,重点是看b(2)对应的弹性是否显著不为 0,也就是置信区间是否包含 0。如果题目给的单品数据量少,可以按品类合并估计,但合并前要检验不同品类的弹性是否同质,否则就是把差异很大的商品混在一起回归,得到的是伪弹性。

4.3 ARIMA日销量基准模型

需求方程描述的是价格与销量的静态关系,但题目第三问要求预测 7 月 1 日到 7 日的单品日需求量,这个任务必须落在时间序列上。我一般把 ARIMA 当基准模型,因为它在样本量不大时比 LSTM 稳定,而且 MATLAB 的arima工具包可以直接估计,不需要额外配置环境。

Mdl = arima(1, 1, 1); % ARIMA(1,1,1) EstMdl = estimate(Mdl, sales_series); [forecast, ~] = forecast(EstMdl, 7, 'Y0', sales_series);

arima(1,1,1)表示 1 阶自回归、1 阶差分、1 阶移动平均。差分的目的是把非平稳序列转成平稳序列,蔬菜日销量有明显的周周期,如果adftest显示不平稳,可以改成对周聚合序列建模,避免过度差分导致信息丢失。

4.4 模型检验:别只盯着R²

回归的 R² 在时间序列里经常虚高,因为趋势项 T 本身就能解释大部分方差,所以模型检验要看更细的指标。我习惯看两个东西:一是残差的自相关函数,用autocorr检查残差是否还有显著的自相关,如果有说明模型没把周期信息抽干净;二是回测的 MAPE,把最后 7 天留出来做样本外预测,计算平均绝对百分比误差。

指标对数线性回归ARIMA
0.83
样本外 MAPE12.4%8.7%
残差滞后7阶自相关显著不显著

从这个表能看到,ARIMA 在纯时序预测上更稳,但回归模型的价值在于能给出弹性和系数解释,两者在最终定价模型里是配合使用的:用回归的弹性写目标函数,用 ARIMA 的预测值校准需求基准。用 Python 复现时,statsmodelsOLSARIMA接口参数含义与 MATLAB 端一致,只有差分项写法略有差别。

5. 定价优化与灵敏度分析:网格搜索与利润最大化

5.1 目标函数与约束条件

定价优化的目标不是销量最大,而是利润最大。对每个单品 j,目标函数是:

max Π = Σ (P_j - C_j) · Q_j(P_j) · (1 - loss_j)

约束条件包括:售价 P_j 在批发价的 1.2 到 2.5 倍之间,这是超市生鲜常见的加价率区间;补货量不超过当日可用库存上限;单品价格不能低于成本价;实际业务里还要考虑促销价与日常价的价差不超过某个阈值,这个阈值在论文里可以作为灵敏度参数来讨论。

5.2 网格搜索求数值解

目标函数高度非线性,用解析求导不现实,最稳妥的做法是网格搜索:把每个品类的价格在可行域里离散成 50 个候选值,计算对应销量和利润,取利润最大的点即可。网格搜索虽然朴素,但在单变量定价问题上效率足够,而且可解释性强,评审容易理解。

p_grid = linspace(C * 1.2, C * 2.5, 50)'; q_est = exp(b(1) + elasticity * log(p_grid) + trend_part); profit = (p_grid - C) .* q_est .* (1 - loss_rate); [~, idx] = max(profit); optimal_price = p_grid(idx);

linspace生成的 50 个候选价覆盖了从 1.2 倍到 2.5 倍批发价的区间,q_est把每个候选价代入回归方程算出预测销量,利润向量里取最大值对应的下标。这里的trend_part是从回归模型里抽出的趋势项和虚拟变量贡献,也可以直接传入 7 月 1 日的预测基准值。网格搜索的粒度决定了最优价的精度,50 个点算出来是 0.1 元一档,够用了;如果后续要更精细,可以在最优点左右再做一轮局部加密搜索。

5.3 灵敏度分析:弹性变了结论还稳吗

论文的审阅者最常问的问题是:你的价格弹性估计有置信区间,那最优定价对弹性敏感吗?做法是把弹性分别替换成置信区间下界和上界,重新跑一轮网格搜索,观察最优价和利润的变化幅度。如果最优价对弹性变化很敏感,说明定价策略脆弱;如果只是小幅偏移,说明结论稳健。

弹性取值最优售价(元/kg)对应利润(万元)
-1.10(下界)6.408.72
-0.86(点估计)5.909.35
-0.62(上界)5.2010.04

这个表说明弹性每向"更需求弹性"方向移动 0.24,最优价就下调约 0.5 元,利润反而上升。结论是:该品类当前处于弹性区间,适当让利能带来更高的总利润,这与超市常见做法一致。写作时把这张表放在灵敏度分析一节,比只贴一个最优解要扎实得多。

5.4 从单品定价回推到补货量

定价和补货是联动的。最优价格确定后,把最优价代入需求方程得到预测销量,再除以(1-损耗率)得到进货量。这一步在代码里就是一行:

replenish_kg = q_est(idx) / (1 - loss_rate);

补货量要做一点修正:如果预测销量高于历史最大日销量的 80%,要回落到该阈值,防止模型在极端价格下给出不切实际的补货建议,这在生鲜场景里对应的是冷藏库容和进货车辆的物理限制。

6. 复现论文时最容易被忽略的三个细节

6.1 先聚合再回归与单品直出的差别

附件里有几百个单品,如果每个单品单独做回归,很多单品只有几十天数据,拟合出来的弹性置信区间会宽到没有意义。我在复现时的做法是:先按品类聚合做趋势分析和弹性回归,得到品类的平均弹性;再把单品价格对品类均价的偏离作为第二层变量并入回归,这样既能保住样本量,又能体现单品差异。代码上就是给回归矩阵多增加一列log(price_single / price_category_mean),系数就是单品相对品类的价格敏感度偏移。

6.2 单位统一:元/kg 与元/件的坑

附件1的销量是 kg,售价是元/kg,但部分数据源里可能混有"件"的单位。如果合并前不统一,回归模型里价格和销量的数量级会完全错位。可以用summary对统一单位后的数据做一个分布对比,单位不一致时中位数会出现异常跳变,这个方法比肉眼检查更可靠。

6.3 验证方式:不要随机打乱数据

时间序列模型的验证和普通回归不一样,随机 K 折会把未来数据混进训练集,造成乐观偏差。我习惯用扩展窗口法:先用第 1-30 天训练、预测第 31-37 天,再把训练窗口扩展到第 37 天预测 38-44 天,滚动下去。代码上就是两层 for 循环,外层控制窗口起点,内层依次向前扩展。用扩展窗口算出的 MAPE 比随机 K 折高 3-5 个百分点,但这才是真实泛化误差,写到论文里经得起复现验证。

这三条如果都能在复现时做到,论文里任何一张图和任何一个系数就都经得起抽查了,这个题目的价值也就真正拿到了。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 18:57:31

先进制造AI+BI试点:生产分析场景包的落地验证方法

导语 不少先进制造企业推进AIBI数字化转型,容易陷入两种误区:要么贪大求全,一上来就推进全工厂全链路落地,导致投入大、周期长,迟迟看不到验证效果;要么盲目试错,随便选个场景上线,验…

作者头像 李华
网站建设 2026/9/11 18:55:48

WSN时间同步原理与MATLAB仿真:时钟偏移估计与CRLB校验

简介:围绕无线传感器网络(WSN)时间同步仿真,MATLAB工程资源完整覆盖了算法实现、性能评估与结果分析环节。资源共18个文件,压缩包大小10.2MB,主要包含可直接运行的m脚本、保存仿真数据的mat文件、记录MSE与…

作者头像 李华
网站建设 2026/9/11 18:53:36

重庆旅游大数据平台:个性化推荐与3D可视化实践

1. 项目背景与核心价值重庆作为中国最受欢迎的旅游城市之一,每年吸引着数以千万计的游客。但面对山城复杂的地理环境和丰富的旅游资源,游客常常陷入"去哪玩""怎么玩"的决策困境。传统的旅游推荐方式存在三个明显痛点:信息…

作者头像 李华
网站建设 2026/9/11 18:52:41

HarmonyOS 7.0 API26 互动卡片幂等 日志定位:桌面卡片连续点击导致重复提交如何处理,从日志、断点和兜底策略一起排查

HarmonyOS 7.0 API26 互动卡片幂等 日志定位:桌面卡片连续点击导致重复提交如何处理,从日志、断点和兜底策略一起排查 这篇只拆一个具体点:HarmonyOS 7.0 API26 互动卡片幂等 / 日志定位。版本边界先放前面:下面的写法面向 Harmon…

作者头像 李华
网站建设 2026/9/11 18:51:18

python自动化如何做的

一、使用库和框架 首先来讲, 它身为可供自动化Web浏览器操作运用的强大工具, 其次呢, 它支持多种浏览器, 同样对于多种编程语言而言, 它也是其中被支持那方, 最后, 它能够在自动化测试里头派上用场, 也能用于数据抓取工作, 还可用在表单填写等各种纷繁别样的任务之中。 使用 …

作者头像 李华