news 2026/9/7 22:43:46

用Mathematica复现竞争零售商渠道策略博弈:从符号推导到均衡区域图

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Mathematica复现竞争零售商渠道策略博弈:从符号推导到均衡区域图

我接触这个项目的时候,刚读完一篇讲竞争零售商渠道策略的中文论文,模型不复杂,但手推公式花了我整整两天,算完还怀疑自己是不是算错了。后来咬咬牙把整套模型搬进 Mathematica,从需求函数、利润函数到均衡价格、渠道结构比较,全部用符号推导加数值实验跑了一遍,效果意外地好。这篇博文就记录一下我完整的复现思路、核心代码逻辑和踩过的坑,希望给同样在跟博弈论渠道论文搏斗的朋友一点参考。

先交代一下这个复现项目的背景,方便你判断这篇文章对你有没有用。我们要复现的论文,简单说就是研究两个相互竞争的零售商,在传统实体渠道、线上自营渠道、线上线下双渠道这几种策略里,最终会选择哪种渠道结构作为博弈均衡。论文里的核心问题是:渠道竞争强度、消费者对线上渠道的接受度、以及零售商之间互相抢客户的程度,会怎样影响均衡结果。

这个工作适合两类人参考:一类是正在做供应链管理、渠道策略相关课题的研究生,想快速验证文献里的结论;另一类是已经在用 Mathematica 做经济学、管理学模型推导的研究者,想看看符号计算在博弈论里能省多少事。如果你还停留在手推公式、再画图的阶段,这篇文章能帮你把整个流程打通。

1. 复现前的准备:先把论文模型拆成可计算的模块

1.1 论文到底在研究什么:模型背景与问题拆解

很多刚接触渠道策略论文的人,拿到文章就急着找代码,结果发现论文里根本没有代码,只有密密麻麻的公式推导。我在复现前做的第一件事,不是打开 Mathematica,而是把论文的模型假设、变量定义和博弈时序全部拆成一个个可以独立计算的小模块。

具体来说,这篇论文的模型框架大致是这样的:

  • 有两个竞争零售商,记为零售商1和零售商2,分别销售同质或近似同质的商品。
  • 每个零售商可以选择两种基本渠道:传统线下渠道(记为 R)和线上渠道(记为 E),也可以同时选择两种渠道(双渠道,记为 D)。
  • 消费者对线下渠道有既有的购物习惯,对线上渠道有一个“接受程度”参数,一般记为 θ,取值范围在0到1之间。θ 越接近1,说明消费者越愿意在线上购买。
  • 渠道之间有替代性,比如消费者本来想去线下店,但如果线上价格便宜,就会转向线上下单,这个替代力度直接影响两个零售商的价格战强度。
  • 两个零售商同时决策渠道结构,然后在给定的渠道结构下进行价格竞争,属典型的两阶段博弈:第一阶段是渠道结构选择,第二阶段是定价竞争。

把这个框架拆清楚以后,我意识到整篇论文的计算核心只有两个:一是给定渠道结构组合下的均衡价格和利润,二是四种渠道结构组合(RR、ER、RE、EE 或带双渠道的更多组合)之间的利润比较,从而画出均衡结构的分区图。

1.2 符号体系统一:复现前先给所有变量“对表”

论文复现最头疼的问题之一,就是符号不统一。不同论文里,同一个参数可能叫 α、β、γ,也可能叫 a、b、c。Mathematica 对大小写敏感,一旦你中途改符号,后面的代码全部要跟着改,非常容易出错。

我的做法是先在纸上把整套符号体系列一张表,写进代码注释里。比如我在这个项目里固定了这样一套命名:

符号含义Mathematica 中写法
( a )市场基础需求量a
( b )零售商自身价格敏感系数b
( d )渠道间的交叉价格敏感系数d
( \theta )消费者对线上渠道的接受度theta
( c )单位销售成本(线上线下可不同)cR, cE
( p_{i,j} )零售商 i 在渠道 j 的价格p[i, j]
( q_{i,j} )零售商 i 在渠道 j 的需求量q[i, j]
( \pi_i )零售商 i 的总利润Pi[i]

统一符号这一小步,看似花时间,实际为我后面省了大量调试时间。如果你复现的是其他论文,也建议先花半小时把符号表列好,这样不管推导到哪一步,代码和数据都能对得上。

1.3 复现路线图:从符号推导到数值实验的四步走

我在动手写代码之前,给自己定了一个四阶段路线,后面所有工作都严格按这条线走,避免想到哪算哪:

  1. 搭建需求函数与利润函数的基本框架,用符号变量表示所有参数。
  2. 对每种渠道结构组合,求解定价阶段的最优反应函数和均衡价格。
  3. 把均衡价格代回利润函数,得到均衡利润,再比较不同渠道结构下的利润大小。
  4. 固定不同参数取值,重复求解,画出渠道结构均衡区域图,和论文原图做对比。

这个路线特别适合博弈论论文的复现,因为博弈论模型天然就是“先解后比”:先解出均衡,再比较不同情形下的数值。后面第三大部分我还会展示每一步对应的 Mathematica 代码片段。

2. Mathematica 符号推导:把“手推公式”变成“机器求导”

2.1 需求函数构造:线性需求模型怎么设置才不失真

渠道策略论文里用得最多的是线性需求模型,因为它既能体现价格竞争,又能方便地求解析解。论文里的需求函数一般这样写:

零售商 i 在线下渠道的需求:( q_{i,R} = a - p_{i,R} + d(p_{j,R} + p_{i,E} - 2p_{i,R}) + \theta \cdot (\text{线上替代效应}) )

当然不同论文写法差异很大,有的会把线上渠道接受度放在需求截距项里,有的会放在交叉项里。我在复现时,遵循的是“保留论文核心机制、简化次要项”的原则:需求函数必须包含价格对自身渠道的负向影响,以及竞争渠道价格的正向影响,否则后面的价格竞争就无从谈起。

以我复现的模型为例,我用了一套比较通用的设定:假设每个零售商在某个渠道的需求,等于基础需求减去自身价格影响,再加上竞争渠道和竞争零售商的价格溢出效应。通过一个参数 ( d ) 控制渠道间的替代强度,通过 ( \theta ) 控制线上渠道的吸引力。

把需求函数写成 Mathematica 代码时,有个小技巧:不要直接写成一长串赋值语句,而是定义成函数形式,方便后面重复调用。我在 Notebook 里这样写:

(* 定义需求函数 *) q[i_, j_, s1_, s2_] := a - p[i, j] + d * (Sum[Sum[p[k, l], {l, Channels[k]}], {k, 2}] - p[i, j]) + theta * If[j == "E", 1, 0]; (* 定义每个零售商的可用渠道集合 *) Channels[1] := {R, E}; Channels[2] := {R, E};

当然这段代码为了展示逻辑进行了简化,实际运行的时候需要根据论文的渠道组合来调整求和范围。这里的关键是:定义函数时,把所有渠道的价格都显式写出来,不要用全局变量,否则后面的求导和代入特别容易混乱。

2.2 一阶条件与最优反应函数:Solve 还是 NSolve 要分清

价格竞争阶段的核心,就是每个零售商在自己的渠道上选择价格,最大化自己的总利润。利润函数很简单:该零售商所有渠道的(价格-成本)×需求之和。

在给定另一家零售商的渠道策略和价格策略时,每个零售商的最优价格通过一阶条件得到:对自身利润函数关于自身价格求偏导,令导数为零,解出价格表达式。

Mathematica 里这一步几乎是“无脑操作”,但有一个容易踩的坑:一阶条件通常是一个线性方程组,Solve 是可以直接求符号解的。但如果论文的模型带了非线性项(比如含 ( p^2 ) 或者服务水平决策),Solve 可能长时间算不出来,这时候要先检查是不是模型设定太复杂,别急着换数值方法。

我当时写的代码大致是这样的:

(* 零售商1的利润函数 *) Pi1[p1R_, p1E_, p2R_, p2E_] := (p1R - cR) * q[1, R, {p1R, p1E}, {p2R, p2E}] + (p1E - cE) * q[1, E, {p1R, p1E}, {p2R, p2E}]; (* 一阶条件 *) eq1R = D[Pi1[p1R, p1E, p2R, p2E], p1R] == 0; eq1E = D[Pi1[p1R, p1E, p2R, p2E], p1E] == 0; (* 求解零售商1的最优反应函数 *) reaction1 = Solve[{eq1R, eq1E}, {p1R, p1E}] // Simplify;

如果你只是想在某个具体参数组合下求数值解,就可以在求解前先把参数赋值,然后用 NSolve。但复现论文解析结论时,最好保留参数符号,因为后面还要做利润比较和参数区间讨论,符号解能直接给出判断条件。

2.3 联立最优反应:均衡价格的形成逻辑

单方面求最优反应是不够的,均衡要求两个零售商的最优反应同时成立,也就是把两家零售商的价格解联立起来。这个“联立”动作背后的经济学直觉是:你定价格的时候,要考虑对方的反应;对方定价格的时候,也要考虑你的反应。最后的结果是大家都选了一个“给定对方价格时自己最优”的价格组合,也就是 Nash 均衡。

代码上实现也不复杂,就是先把两个零售商各自的一阶条件列出来,然后用 Solve 一次性解方程组。不过这里要特别注意:如果零售商可以选择双渠道,那么价格变量会非常多,比如零售商1有线下价和线上价,零售商2也有线下价和线上价,方程组可能会有四五个方程。解出来的表达式会非常冗长。

长表达式是 Mathematica 符号推导中最大的敌人。我的经验是,每解出一个均衡价格,立刻用 Simplify 或者 FullSimplify 化简,然后存成一个规则列表。后面要算利润时,直接把这个规则代入,千万不要把整串表达式复制来复制去,那样子既容易出错,又拖慢计算速度。

(* 联立求解均衡价格 *) eqs = {eq1R, eq1E, eq2R, eq2E}; soln = Solve[eqs, {p1R, p1E, p2R, p2E}] // FullSimplify; (* 保存最终均衡价格规则 *) equilibriumPrice = soln[[1]];

这里下标[[1]]也是一门学问:Solve 可能返回多个解,但在线性需求模型下通常只有一个经济上合理的解,即价格为正、利润为正的解。如果出现多解,一定要手动检查哪个解符合价格非负的条件,别直接拿第一个解就用。

3. 实操现场:四种渠道结构组合的计算与比较

3.1 渠道结构场景枚举:RR、RE、ER、EE 还是带 D?

在论文模型里,两个零售商各选一种或两种渠道,组合起来会有多种结构。常见的有:

  • 都只开线下:RR
  • 零售商1开线下,零售商2开线上:RE
  • 两边都开双渠道:DD
  • 一方双渠道、另一方单渠道:DR、DE

这里需要特别提醒:组合本身不是越多越好。论文里如果只分析了几种代表性组合,你就没必要把所有可能组合全枚举一遍,否则算力消耗大且展示重点不突出。我当时是把论文里面原有的组合场景逐个实现,然后额外补充了一个“双渠道 vs 双渠道”的场景,作为自己的一点扩展。

对于每一个场景,我写了一个统一的函数,输入是两个零售商各自选择的渠道集合,输出是均衡价格和均衡利润。这样做的好处是代码复用率极高,不需要每个场景都复制粘贴一遍求解逻辑。

(* 通用计算函数:给定渠道集合,返回均衡价格与利润 *) computeEquilibrium[ch1_, ch2_] := Module[ {prices, profits}, prices = solveForPrices[ch1, ch2]; profits = computeProfits[prices, ch1, ch2]; {prices, profits} ];

3.2 利润比较与渠道结构选择博弈

有了四个场景下的均衡利润,下一步就是画一个 ( 2 \times 2 ) 的支付矩阵,看看两个零售商在“选线下”还是“选线上”之间,最终会落在哪个均衡。

这步用 Mathematica 做非常直观:把每个零售商在四种组合下的利润列成一个矩阵,再根据利润大小判断最优反应。比如给定零售商2选了线下,零售商1比较自己选线下和选线上的利润,哪个高就选哪个;给定零售商2选了线上,再比较一次。最后找出一组“互为最优反应”的策略,那就是纯策略 Nash 均衡。

代码层面其实不需要复杂的博弈论工具包,用最原始的嵌套判断就能算出来:

(* 四种组合利润 *) profitTable = { {"RR", Pi1RR, Pi2RR}, {"RE", Pi1RE, Pi2RE}, {"ER", Pi1ER, Pi2ER}, {"EE", Pi1EE, Pi2EE} }; (* 判断零售商1基于零售商2策略的最优反应 *) bestResponse1[ch2_] := Which[ profit1[{"R", ch2}] >= profit1[{"E", ch2}], "R", True, "E" ];

这个过程就是要解决论文里最核心的问题:竞争零售商最终会走向线上化,还是继续维持线下,还是变成双渠道混战?答案往往取决于参数,比如线上接受度和渠道替代强度。复现到这里,我已经能看懂论文主图的生成逻辑了。

3.3 数值实验:参数扫描与三维图复现

符号推导做完了,论文里很多结论是靠数值实验和图形呈现的,这时候就需要用参数扫描画出均衡区域图。我看过很多新手在这一步犯同一个错误:直接拿循环跑上百组参数,每组都用 Solve 求一次解析解,结果跑得奇慢无比。

正确的做法是分两步:第一步,在符号层面完成所有求解,把均衡价格的表达式存好;第二步,在数值实验阶段,把参数代入表达式中快速计算,而不是每次都重新求解。相当于把“求公式”和“代数字”两件事分离开了。

我在复现“渠道结构均衡区域图”时,写了一个双重循环:横轴是线上渠道接受度 ( \theta ),纵轴是渠道替代强度 ( d ),对每个参数组合判断哪种渠道结构是 Nash 均衡,然后用 RegionPlot 画出分区颜色图。

(* 参数扫描判断均衡 *) equilibriumStruct[thetaVal_, dVal_] := Module[ {payoffs, eq}, payoffs = computeAllPayoffs /. {theta -> thetaVal, d -> dVal}; eq = findPureNash[payoffs]; eq ]; RegionPlot[ equilibriumStruct[theta, d] == "RR", {theta, 0, 1}, {d, 0, 1}, PlotStyle -> Blue, PlotPoints -> 50 ]

这张图如果手画,工作量巨大;用 Mathematica 的 RegionPlot,几分钟就能出图。但前提是你已经把符号推导部分做得足够干净,否则参数代入的时候会报一堆 “Power::infy” 或者 “Infinity::indet” 的错误,到时候排查起来非常头疼。

4. 复现过程中的坑与排查技巧

4.1 符号表达式太长:FullSimplify 不是万能的

第一道坎就是表达式太长。当你解出四价格方程组时,输出的表达式可能连续十行都写不完,直接看根本看不出经济含义。这时候你可能会想到 FullSimplify,但 FullSimplify 在变量多的时候,计算时间会急剧上升,有时候一分钟都算不完一个式子。

我的经验是:先尝试 Simplify,等确认结果正确后,再有针对性地用 FullSimplify 处理要用于绘图的式子。还有一种节省时间的办法,是把公共项提取出来,用Collect按某个变量整理,让表达式结构更清晰。实际项目里,按thetad做 Collect 之后,很多看似混乱的项会突然变得有规律,后面数值代入也快很多。

(* 结构化化简 *) Collect[Simplify[soln[[1, 1, 2]]], {theta, d}]

4.2 均衡解出现负价格或负需求:先查参数范围

论文复现中最常见、也最容易让新手懵的现象,就是解出来的均衡价格或者均衡需求是负数。这不一定是你代码错了,很多数理模型在特定参数区域就会产生不合理的“数学解”,但论文中通常只关注有经济意义的参数空间。

我当时遇到负价格的第一反应是检查代码,后来才意识到要先把参数约束加进求解过程。比如 ( 0 < \theta < 1 )、( 0 < d < b ) 这类条件,尤其在数值实验阶段,务必要在参数扫描前用Assumptions声明,或者直接在 RegionPlot 里限定坐标范围。这样不仅避免了无意义的解,也让均衡区域图更贴合论文原图。

另一个容易出问题的地方是交叉价格系数 ( d ) 的取值范围。d 必须小于自身价格系数 b,否则需求函数丧失了“自身价格影响大于交叉影响”的基本性质,会导致荒谬的结果。很多论文的原图能画出来,就是因为参数范围选得对,这一点在复现时一定要留意。

4.3 不同文献符号差异大:不要照搬代码,建立自己的模块

最后想强调一点:复现论文不是把别人的代码拿过来跑一遍,而是理解模型逻辑后用工具重建。我一开始也尝试找原作者是否有公开代码,但大多数渠道策略论文只提供公式和图形,没有代码附录。所以最终还是回到了“读公式—写代码—对图”这个流程上。

不同论文即使模型相似,符号体系和假设也可能不同,比如有的论文假设线上渠道成本为零,有的论文假设线上渠道有额外物流成本。这些微观差异对均衡结果影响很大,照搬别人的代码反而容易出错。所以我会针对每个论文,建立一套自己的符号和函数模块,即使效率低一点,也好过在别人的代码里找哪里该改、哪里不该改。

5. 写在最后的实操心得

这次复现做完,最大的感受是 Mathematica 特别适合这种“符号推导 + 参数扫描 + 区域图”三位一体的博弈论论文复现。它不像手推那样容易出错,也不像纯数值仿真那样看不到公式结构。只要你把需求函数、利润函数、均衡求解和绘图拆成清晰的模块,一篇论文从想法到出图,基本可以压缩在一天内完成。

给你一个直接的建议:不管你复现什么论文,先从复现一两个关键图开始,不要一上来就想把整篇论文所有拓展全部实现。先把主模型跑通,确认你的结果曲线和论文原图长得一致,再逐步加入参数变化、灵敏度分析和扩展场景。这样每一步都有对照,出错也能快速定位。

如果再往前扩展一步,这套代码还很容易改成双渠道加服务竞争的模型,因为核心的博弈求解框架是通用的,只需要增加一个服务变量和对应的成本函数。我现在就是这么做的,后续如果跑出新结果,再来分享更多细节。

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

python GIL全局解释器锁的理解

GIL的全称为Lock, 其意思是全局解释器锁, 这个GIL并非其特性, 它是仅在解释器里得以引入的某个概念, 而于其他语言所编写成的解释器里面就不存在这个GIL, 例如Pypy。为什么会有gil&#xff1f;&#xff1a;因为电脑出现多核CPU以及CPU频率得到提升因而为充分利用多核处理器多线…

作者头像 李华
网站建设 2026/9/7 22:41:23

支持云盘在线播放的Apple TV软件推荐2026

想在 Apple TV 上直接在线播放阿里云盘、百度网盘里的视频&#xff0c;不是靠单一 App 就能通吃&#xff0c;但用对播放器可以少走弯路。2026 年比较稳的方案有三类&#xff1a;Plex 适合有媒体库需求的用户&#xff0c;nPlayer 适合文件夹直连党&#xff0c;Kodi 配合 Alist/W…

作者头像 李华
网站建设 2026/9/7 22:41:05

MyPy 安装与配置快速教程:新手如何第一次跑通静态类型检查

MyPy 安装与配置快速教程&#xff1a;新手如何第一次跑通静态类型检查 【免费下载链接】mypy Optional static typing for Python 项目地址: https://gitcode.com/GitHub_Trending/my/mypy 写 Python 时最坑的类型 bug&#xff0c;往往要等程序跑起来才暴露。MyPy 在代码…

作者头像 李华
网站建设 2026/9/7 22:40:17

2026深度解读:Work Agent与传统办公系统的能力差异

2026深度解读&#xff1a;Work Agent与传统办公系统的能力差异 办公软件已经深度渗透企业日常业务&#xff0c;文档协作、流程审批、报表统计等工具承担着组织内大部分标准化工作。伴随AI Agent技术落地&#xff0c;一类可以自主完成长链任务的工作助手开始进入办公场景。不少从…

作者头像 李华
网站建设 2026/9/7 22:38:29

芯片赛道开发者切入指南:MCU架构、选型与工具链深度拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华