ARTICLE DETAIL

资讯详情

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

双渠道闭环供应链跨渠道退货定价:Stackelberg与Nash均衡求解

双渠道闭环供应链跨渠道退货定价:Stackelberg与Nash均衡求解 简介一份面向供应链管理研究人员、高校物流相关专业师生及双渠道销售企业管理者的完整PDF资源聚焦考虑跨渠道退货的双渠道闭环供应链决策优化。内容系统整合Stackelberg博弈与Nash均衡模型对比集中式、制造商主导、零售商主导及Nash均衡结构下的定价策略并通过Python代码实现参数定义、需求函数构建、最优化求解与利润对比涵盖消费者渠道偏好、退货率等关键变量的敏感性与非线性关系分析。PDF共1个文件包体约624KB内含可运行的模型复现代码及逐步解释便于读者快速复现研究结果也可直接用于实际数据验证。目前已有41人学习下载适合需要深入理解跨渠道退货影响机制、掌握不同博弈结构下最优定价与利润分配规律以及寻求退货政策与收益共享契约设计参考的研究者和企业管理者。1. 双渠道闭环供应链的定价困局退货处理不好利润表和渠道关系一起崩考虑跨渠道退货的双渠道闭环供应链决策优化本质上是在回答一个问题当一个品牌的线上订单被顾客拿到线下门店退货这笔退货损失该算谁的、价格该怎么定、渠道利润该怎么分。这不是单纯的物流成本题而是Stackelberg博弈和Nash均衡同时存在的定价决策题——制造商线上直销和线下零售商之间既有主从关系又在同一市场争夺顾客退货品进入再制造闭环后又反过来影响新品的定价空间。我最早跑这类模型时以为多设几个退货参数就能出结果实际做下来发现跨渠道退货的核心不在“退了多少”而在“退回来的货由谁承担处理成本、谁享受再制造成本节约”。这两个主体不一致Stackelberg主导方和Nash均衡下的利润分配结果能差出一倍。这篇文章给出完整建模过程、Python求解代码和五类高频踩坑点适合做供应链定价研究、电商平台规则设计或毕业课题复现的从业者。2. 把“跨渠道退货”写进模型需求函数、成本结构与博弈顺序2.1 跨渠道退货如何改变双渠道的净需求双渠道闭环供应链里有两条正向销售渠道制造商自营的线上直销渠道和线下零售商渠道。传统双渠道模型只写两个需求函数比如线上需求对线上价格敏感、对线下价格交叉敏感。一旦引入跨渠道退货事情变复杂顾客在线上看中商品、下单、收货然后拿到线下门店退货。线下门店因此产生验货、入库、二次包装的人工成本这笔成本如果全部由零售商承担零售商的利润会被退货率一点点吃掉。建模时我把线上渠道的原始需求记为D_d a_d - α * p_d β * p_r线下渠道需求为D_r a_r - α * p_r β * p_d其中α是渠道自身价格敏感系数β是交叉价格敏感系数。跨渠道退货对两个渠道的需求都产生修正线上退货量λ_d * D_d最终发生在线下门店这部分货既不能在线上形成净收入又给零售商带来单位处理成本c_h。制造商如果不想让零售商拒绝处理退货就必须给零售商单位补偿s。于是零售商的净利润里多了一项(s - c_h) * λ_d * D_d制造商的净利润里多了一项负向的- s * λ_d * D_d同时节省了新品制造成本因为退回来的货可以翻新再售或拆解再利用。真正让模型有意思的是退货品与再制造闭环的耦合退回来的货越多可再制造的材料基数越大但退货也直接侵蚀了当期净需求。两个效应方向相反定价高了退货少、再制造收益少定价低了销量大、退货处理成本也大。最优价格不是一个固定值而是退货率、补偿系数、再制造成本节约共同作用下的均衡点。2.2 Stackelberg与Nash均衡在供应链定价里的区别博弈顺序决定了求解方法。Stackelberg博弈适合“制造商主导、零售商跟随”的渠道结构制造商先决定批发价w、线上直销价p_d和回收率τ零售商观察到这些决策后再决定自己的线下零售价p_r。求解时先算零售商的反应函数再把反应函数代回制造商的利润函数做外层优化。这里的核心是Stackelberg 均衡体现的是“领导者利用先动优势”领导者可以把价格定在让跟随者刚好能接受的位置从而拿走大部分渠道利润。Nash均衡则适合两个渠道主体同时决策的场景制造商和零售商各自优化自己的利润谁都不先动。此时联立一阶条件求交点。Nash均衡和Stackelberg均衡的结果通常不一样Stackelberg 主导方利润更高跟随方利润更低而 Nash 均衡下双方的利润更接近但总利润可能低于集中决策。原因在于双重边际化——各渠道只考虑自身毛利批发价抬高导致最终零售价过高总销量被压缩。我一般建议研究者在建模前先想清楚一个问题你所在的行业是制造商强势还是零售商强势强势方不同博弈顺序就不同最优定价策略也完全不同。零售巨头主导的供应链适合让零售商做 Stackelberg 领导者品牌制造商主导的供应链才适合制造商领导。标题里的“Stackelberg博弈和Nash均衡”其实是在做对比研究不是只求一种均衡。2.3 参数表与决策变量没有一套参数后面的代码全是空谈模型里每个参数都有经济含义参数值不同均衡结果可能从“线上低价”翻转到“线下低价”。我常用的参数基准如下。参数含义基准值备注a_d线上渠道基础市场规模100大于a_r时线上渠道市场潜力更大a_r线下渠道基础市场规模80α自身价格敏感系数2.0必须大于ββ交叉价格敏感系数0.8渠道间替代强度β α保证均衡存在c_n新品单位制造成本10c_r再制造单位成本4Δ c_n - c_r为单件再制造成本节约λ_d线上渠道跨渠道退货率0.15落在[0, 1)超过 0.3 模型对补偿敏感c_h零售商处理跨渠道退货的单位成本2.0含验货、包装、库存占用s制造商给零售商的单位退货补偿1.5合同外生参数谈判可调整c_t制造商对退货品的返修处理成本1.0返修后再进入再制造η回收努力成本系数20回收成本是凸函数η * τ²Δ再制造单件成本节约c_n - c_r 6决策变量一共四个批发价w、线上直销价p_d、线下零售价p_r、回收率τ。其中w、p_d、τ由制造商决策p_r由零售商决策。跨渠道退货补偿s作为外生合同参数在利润分配章节再讨论它的谈判空间。回收率τ控制着闭环供应链的回收规模回收量设为τ * (D_d D_r)回收努力成本为η * τ²。这个二次成本函数很关键它保证了回收率不会无限膨胀——边际回收成本递增均衡回收率一定在0到1之间。若用线性回收成本函数均衡点可能跑到边界上数值求解时容易报错。3. 从博弈到PythonStackelberg与Nash均衡的完整求解代码3.1 先写利润函数与零售商反应函数我把求解代码分成三层底层是参数类与利润函数中间是零售商反应函数顶层是两种博弈的求解器。先定义参数结构方便后面做敏感性分析时批量改参。from dataclasses import dataclass import numpy as np from scipy.optimize import minimize, root dataclass class SupplyChainParams: a_d: float 100.0 # 线上基础需求 a_r: float 80.0 # 线下基础需求 alpha: float 2.0 # 自身价格敏感系数 beta: float 0.8 # 交叉价格敏感系数 c_n: float 10.0 # 新品制造成本 c_r: float 4.0 # 再制造成本 lam_d: float 0.15 # 线上渠道跨渠道退货率 c_h: float 2.0 # 零售商退货处理成本 s: float 1.5 # 制造商给零售商的退货补偿 c_t: float 1.0 # 制造商返修处理成本 eta: float 20.0 # 回收努力成本系数 property def delta(self): return self.c_n - self.c_r # 再制造单件成本节约 def demands(p_d, p_r, p: SupplyChainParams): D_d p.a_d - p.alpha * p_d p.beta * p_r D_r p.a_r - p.alpha * p_r p.beta * p_d return D_d, D_r def retailer_profit(p_d, p_r, w, p: SupplyChainParams): D_d, D_r demands(p_d, p_r, p) # 零售商卖新品赚差价同时处理跨渠道退货赚补偿差 return (p_r - w) * D_r (p.s - p.c_h) * p.lam_d * D_d def manufacturer_profit(p_d, w, tau, p_r, p: SupplyChainParams): D_d, D_r demands(p_d, p_r, p) rec_volume tau * (D_d D_r) # 回收总量 rec_cost p.eta * tau**2 # 回收努力成本 return (w * D_r (p_d - p.c_n) * D_d - p.s * p.lam_d * D_d # 给零售商的退货补偿 - p.c_t * p.lam_d * D_d # 返修处理成本 p.delta * rec_volume # 再制造成本节约 - rec_cost) def retailer_reaction(p_d, w, p: SupplyChainParams): # 零售商利润对 p_r 求一阶导并令其为零 # d(pi_R)/dp_r a_r - alpha*p_r beta*p_d - alpha*(p_r - w) 0 return (p.a_r p.beta * p_d p.alpha * w) / (2 * p.alpha)这段代码的逻辑有几个关键点。需求函数里的β参数是渠道间的交叉影响它模拟的是顾客比价行为线上价格涨了一部分顾客转向线下线下价格涨了一部分顾客转向线上。零售商利润里多出的(p.s - p.c_h) * p.lam_d * D_d项不是凭空想象的收入它对应的是“线上订单线下退货”场景下零售商代制造商处理退货获得的补偿净额。如果补偿s小于处理成本c_h零售商就没有动力配合退货这部分在模型里直接体现为负利润。retailer_reaction返回的是零售商的最优价格反应函数这个函数是解析解不需要数值优化。它的推导逻辑是零售商利润是p_r的二次函数开口向下-α项保证二阶导为负所以一阶条件就是利润最大化的充要条件。这里p_r的表达式中同时出现p_d和w直观含义是线上直销价越高线下越有涨价空间批发价越高零售商的成本越高零售价自然跟着涨。3.2 Stackelberg主从博弈求解外层优化内层反应制造商是 Stackelberg 领导者时它预判零售商会按反应函数定价所以把p_r替换成retailer_reaction再优化自己的利润。这里我用scipy.optimize.minimize处理。def stackelberg_solve(p: SupplyChainParams, x0None): if x0 is None: x0 np.array([12.0, 30.0, 0.5]) # [w, p_d, tau] def neg_profit(x): w, p_d, tau x p_r retailer_reaction(p_d, w, p) return -manufacturer_profit(p_d, w, tau, p_r, p) bounds [(5, 50), (5, 80), (0.0, 0.95)] res minimize(neg_profit, x0, methodSLSQP, boundsbounds) w, p_d, tau res.x p_r retailer_reaction(p_d, w, p) pi_m manufacturer_profit(p_d, w, tau, p_r, p) pi_r retailer_profit(p_d, p_r, w, p) return { w: w, p_d: p_d, p_r: p_r, tau: tau, pi_m: pi_m, pi_r: pi_r, solver: res }这里minimize优化的是neg_profit因为我用的是 SLSQP 算法它默认找最小值供应链利润最大化问题要取负号才能套进去。边界约束里的w下限设为 5 是因为如果批发价低于再制造成本制造商更愿意收回所有货做再制造而不是卖给零售商这属于模型边界条件我在避坑章节会展开。零售商反应函数retailer_reaction返回的p_r不能超过(a_r β*p_d α*w) / (2α)这个自然上界所以即使外层优化尝试了很多w和p_d的组合内层反应函数始终是解析解不会像嵌套数值优化那样出现“内层不收敛”的问题。这也是我坚持把零售商反应函数手推成解析式的原因——嵌套优化每一层多一次数值求解整体计算量翻倍且更容易踩局部最优。3.3 Nash均衡求解不动点迭代与方程组求根Nash均衡的求解思路是认为制造商和零售商同时决策。制造商决策变量是w、p_d、τ零售商决策变量是p_r四个一阶条件联立求根。我直接用scipy.optimize.root把一阶条件写成残差向量。def nash_solve(p: SupplyChainParams, x0None): if x0 is None: x0 np.array([12.0, 30.0, 20.0, 0.5]) # [w, p_d, p_r, tau] def focs(x): w, p_d, p_r, tau x D_d, D_r demands(p_d, p_r, p) rec_volume tau * (D_d D_r) # d(pi_R)/dp_r 0 foc_r p.a_r - 2 * p.alpha * p_r p.beta * p_d p.alpha * w # d(pi_M)/dp_d 0 d_pi_dpd (p.a_d - 2 * p.alpha * p_d p.beta * p_r p.alpha * p.c_n (p.beta - p.alpha) * p.lam_d * (p.s p.c_t) - (p.delta * tau) * (p.alpha - p.beta)) # d(pi_M)/dw 0 d_pi_dw (p.a_r - p.alpha * p_r p.beta * p_d - p.alpha * (w - p.c_n) p.lam_d * (p.s p.c_t) * p.beta - p.delta * tau * (p.alpha - p.beta)) # d(pi_M)/dtau 0 d_pi_dtau p.delta * (D_d D_r) - 2 * p.eta * tau return [d_pi_dw, d_pi_dpd, foc_r, d_pi_dtau] # 注意这里返回顺序与 x 顺序一致 res root(focs, x0, methodhybr) w, p_d, p_r, tau res.x pi_m manufacturer_profit(p_d, w, tau, p_r, p) pi_r retailer_profit(p_d, p_r, w, p) return { w: w, p_d: p_d, p_r: p_r, tau: tau, pi_m: pi_m, pi_r: pi_r, solver: res }Nash均衡的代码比 Stackelberg 短但实际更易翻车。:hybr方法用的是 Powell 混合算法它对初值敏感我遇到多次“求出的根是负价格”的情况。这里的d_pi_dpd和d_pi_dw两个一阶条件展开时必须把跨渠道退货项和回收项对各自决策变量的偏导数算全。举个例子p_d变化时它不只影响D_d还影响D_r通过交叉项β进而影响回收量τ * (D_d D_r)。很多初写者在d_pi_dpd里漏掉- p.delta * tau * alpha这一项只保留退货补偿部分结果均衡线上价格明显偏离真实值。我在代码里直接用展开后的解析导数而没有用自动微分就是为了让每一行都能跟论文里的推导公式对上。3.4 两种博弈结果的对比输出求解器写好后直接对比两组结果。if __name__ __main__: p SupplyChainParams() stack stackelberg_solve(p) nash nash_solve(p) print(Stackelberg 均衡: w%.2f p_d%.2f p_r%.2f tau%.3f | pi_m%.2f pi_r%.2f % (stack[w], stack[p_d], stack[p_r], stack[tau], stack[pi_m], stack[pi_r])) print(Nash 均衡: w%.2f p_d%.2f p_r%.2f tau%.3f | pi_m%.2f pi_r%.2f % (nash[w], nash[p_d], nash[p_r], nash[tau], nash[pi_m], nash[pi_r]))输出结果通常表现为Stackelberg 均衡下批发价和线上直销价更高零售商利润被压缩Nash 均衡下双方定价更温和总利润略高但仍低于集中决策。你如果跑出“Nash 均衡价格反而高于 Stackelberg”的结果优先检查交叉价格敏感系数β是不是设置得和α太接近极端情况下会直接导致均衡不存在数值求解器返回的根没有经济意义。示例输出基准参数 Stackelberg 均衡: w17.32 p_d30.15 p_r38.24 tau0.42 | pi_m612.30 pi_r198.45 Nash 均衡: w15.81 p_d28.40 p_r36.12 tau0.38 | pi_m548.72 pi_r286.63以上数值是演示形态实际跑出来的数会随scipy版本和初值浮动但量级关系是稳定的Stackelberg 领导者的利润更高、跟随者利润更低这是主从博弈的先动优势在定价上的体现。看到这个对比才能理解为什么渠道强势方一定要争取“先定价”的权力。4. 利润分配用Nash协商把合作剩余分到不“翻车”4.1 分散决策下双重边际化有多严重把 Stackelberg 均衡的总利润与集中决策总利润对比就能量化双重边际化的损失。集中决策相当于制造商和零售商合并成一家公司统一决策p_d和p_r最大化总利润没有批发价这个中间环节。def centralized_solve(p: SupplyChainParams, tau_fixedNone): def neg_total(x): p_d, p_r, tau x D_d, D_r demands(p_d, p_r, p) rec_volume tau * (D_d D_r) rec_cost p.eta * tau**2 total ((p_d - p.c_n) * D_d (p_r - p.c_n) * D_r - (p.c_t p.c_h) * p.lam_d * D_d p.delta * rec_volume - rec_cost) return -total x0 np.array([35.0, 35.0, 0.5]) bounds [(5, 80), (5, 80), (0, 0.95)] res minimize(neg_total, x0, methodSLSQP, boundsbounds) p_d, p_r, tau res.x return p_d, p_r, tau, -res.fun集中决策下没有批发价线上和线下统一定价思路退货处理成本由“公司”整体承担。对比结果通常显示集中决策总利润比分散决策高 15% 到 30%。差异来自双重边际化分散决策时零售商在批发价之上再加一层毛利导致最终零售价偏高、总销量萎缩。4.2 Nash协商解的计算代码合作总利润比分散决策总利润高出部分就是合作剩余。如何分配这笔剩余我使用 Nash 协商解——它要求分配结果让双方利润都高于不合作的威胁点且满足帕累托最优。数学形式是在约束两方利润不低于威胁点条件下最大化协商函数max (φ_M - π_M^0) * (φ_R - π_R^0) s.t. φ_M φ_R ≤ π_C, φ_M ≥ π_M^0, φ_R ≥ π_R^0威胁点π_M^0和π_R^0取 Stackelberg 均衡利润或 Nash 均衡利润均可我默认用 Stackelberg 均衡利润因为现实中制造商强势时威胁点就是领导者的“不合作保底利润”。def nash_bargaining(p: SupplyChainParams, threat_m, threat_r): pi_C centralized_solve(p)[-1] total_surplus pi_C - threat_m - threat_r def neg_bargain(phi_m): phi_r pi_C - phi_m if phi_m threat_m or phi_r threat_r: return 1e10 return -( (phi_m - threat_m) * (phi_r - threat_r) ) res minimize(neg_bargain, x0np.array([threat_m total_surplus/2]), methodSLSQP, bounds[(threat_m, pi_C)]) phi_m res.x[0] phi_r pi_C - phi_m return phi_m, phi_r, pi_C, total_surplus这个求解把二维约束优化压成了一维搜索给定φ_Mφ_R自动等于π_C - φ_M协商函数变成单变量函数SLSQP很容易收敛。如果跑出来φ_M贴在下边界上说明制造商的威胁点利润太高合作剩余根本不足以让零售商接受合作此时应该检查是不是参数设置让零售商在分散决策下几乎没有利润。Nash协商分配的结果在基准参数下通常是制造商拿到合作剩余的大头零售商拿到的增量与其威胁点利润成比例。这一结果和直觉一致威胁点利润越高谈判中要价能力越强分到的剩余越多。4.3 分配比例的边界讨论Nash协商解不是唯一的利润分配方案Shapley值也常用。但 Shapley 值要求先定义所有子联盟的利润特征函数在大联盟超可加性不满足时会出现负分配额。这里的“超可加性”指任意两个子联盟合并后的利润不低于分开的利润之和。在跨渠道退货模型里制造商和零售商单独经营的利润之和很可能大于合作利润因为单干时不需要互相承担退货补偿。若此时硬算 Shapley 值某个主体会分到负数。所以我更推荐 Nash 协商解它只需要大联盟利润和两个威胁点利润数据需求少且天然保证分配结果不低于威胁点。如果你想在论文里同时报告 Shapley 值必须先验证特征函数的超可加性具体验证方法就是把制造商单干利润、零售商单干利润、两者合作利润放在同一张表里对比。5. 避坑清单从模型推导到代码复现的5个高发事故5.1 退货率写成常数均衡结果直接失真现象把λ_d设成固定值 0.15跑敏感性分析时发现退货率从 0.1 调到 0.3定价和利润的变化方向不符合业务直觉——退货率上升线上价格反而下降。原因退货率其实不是独立的常数它通常与价格相关。价格越高顾客对商品期望越高越容易因“不符合预期”退货。模型里把退货率写死相当于切断了价格对退货的影响路径。解决把退货率建模为线上价格的增函数常见做法是λ_d λ0 γ * p_d其中γ是价格对退货率的边际影响系数。这样价格和退货率形成内生联动定价模型才能反映“高价高退货”的真实权衡。5.2 二阶条件没验证最优解其实是“最差解”现象手推零售商反应函数时一阶导数算对了但求出的p_r使零售商利润取最小值而不是最大值。原因一阶条件是驻点条件既可能是极大值也可能是极小值。零售商利润对p_r的二阶导数是-2α只有α 0才是凹函数、驻点是极大值。把α设成负数或没检查 Hessian 矩阵就会得到完全反向的结论。解决在推导每个反应函数后额外写一行二阶导数验证。代码里体现为对retailer_profit再求一次p_r的二阶导数或直接数学验证-2α 0。Stackelberg 外层优化同理用minimize求解后最好用结果附近的网格点重新计算利润确认没有比当前解更优的点。5.3 Stackelberg嵌套求解对初值敏感局部最优骗过所有人现象换了一组初值minimize返回的批发价和线上价格完全不同且后者的总利润明显更高。原因制造商利润函数关于w、p_d、τ不是全局凹函数SLSQP是局部优化算法初值落在不同盆地里就返回不同局部最优。这是嵌套优化叠加非凸函数的典型翻车场景。解决用多起点策略。我习惯跑 20 组随机初值取利润最高的结果并用网格扫描验证。具体做法是让w在[c_n, 2*c_n]之间取 10 个值p_d在[20, 60]之间取 10 个值τ在[0.1, 0.9]之间取 5 个值每组组合作为初值运行一次求解器。成本是 500 次求解换来的是均衡结果的稳定性。5.4 跨渠道退货成本只记在制造商头上零售商利润失真现象模型里把退货返修成本c_t和零售商处理成本c_h都算作制造商的支出零售商利润只剩卖货差价。跑出来零售商利润极高制造商利润极低利润分配结果完全不符合行业认知。原因现实场景中跨渠道退货发生在线下门店零售商的人工成本已经发生。如果模型里只有制造商承担退货相关成本相当于零售商白干活还能从补偿中获利利润虚高制造商承担了全部处理成本利润虚低。解决把零售商处理成本c_h写进零售商利润函数制造商通过补偿s承担一部分。补偿s与外生参数的关系是s c_h时零售商净承担退货成本s c_h时零售商从退货处理中赚服务费。这个参数是渠道博弈的谈判焦点也可以在利润分配章节把它当决策变量内化。5.5 回收率与退货率共用符号代码静默出错现象代码能跑通但回收率计算结果大于 1或者退货率变化时回收率完全不变。原因变量命名混乱。我在初版代码里把回收率写成tau把退货率写成lambda_d某次重构后把退货率误写成tau的表达式回收率直接变成了退货率与需求量的乘积导致回收率超过 1 这类明显异常结果。Python 不会因为变量重名报警模型结果却彻底失效。解决强制命名规范退货率一律用lam_d回收率一律用tau再制造节约用delta。每段代码开头用注释声明变量含义。另外在求解后加断言assert 0 tau 1保证回收率落在可行域内。这个小习惯帮我提前拦下过两次静默污染。6. 均衡唯一性与敏感性分析验证模型不是“黑匣子”的最后一道工序6.1 参数扫描与均衡轨迹可视化当模型跑通后我建议做三件事参数扫描、均衡唯一性判断、灵敏度分析。这三步能回答“这个模型是不是我随手调参调出来的”这个灵魂拷问。参数扫描常用做法是把高关注度的参数等距取几十个值逐个求解均衡画出均衡轨迹。比如s制造商给零售商的退货补偿从 0.5 扫到 3.0观察p_d、p_r、双方利润如何变化。可以预期的是补偿越高零售商越愿意接受退货但制造商成本越高线上价格会被推高。若扫描曲线出现跳变点说明模型在某个参数区间存在多重均衡此时不能只看一个点下的结论。def sensitivity_scan(param_name, values, solve_func): results [] for v in values: p SupplyChainParams() setattr(p, param_name, v) sol solve_func(p) results.append(sol) return results这段通用扫描代码的要点是每次从默认参数复制新实例避免参数污染。我建议你同时输出均衡解和求解器收敛标志solver.success如果某个参数点求解失败就能准确定位到是哪一段区间出了问题而不是整个扫描静默失败。6.2 反应函数斜率条件与均衡唯一性判断Nash均衡唯一性的充分条件在双渠道模型中就是交叉价格敏感系数小于自身价格敏感系数β α。这个条件的直观解释当线上价格上升 1 单位线上需求下降α单位同时线下需求上升β单位。如果β α说明渠道间替代效应强于渠道自身价格效应一个渠道涨价反而让另一个渠道需求更大反弹反应函数斜率大于 1两条反应函数可能出现多个交点甚至相切。用图形验证时把零售商反应函数画成以p_r为纵轴、p_d为横轴的曲线把制造商反应函数画成p_d为纵轴、p_r为横轴的曲线在同一坐标系里看交点数量。这个交点在β α下通常只有一个因为零售商反应函数斜率是β / (2α)等于 0.2 左右制造商反应函数的斜率类似两条斜率小于 1 的曲线最多交一次。这是模型理论上的逆向验证手段我强烈建议写进论文附录。6.3 一个值得保留的验证脚本最后一个技巧是给求解器加一个“合理性校验”函数把结果同时放入原始利润函数和网格点利润列表里检查。具体实现可以用数值差分验证一阶条件残差是否接近 0这是验证导数推导和求解器收敛的黄金标准。def validate_focs(sol, p: SupplyChainParams, solve_typenash): eps 1e-6 if solve_type nash: x np.array([sol[w], sol[p_d], sol[p_r], sol[tau]]) w, p_d, p_r, tau x D_d, D_r demands(p_d, p_r, p) foc_r p.a_r - 2*p.alpha*p_r p.beta*p_d p.alpha*w print(fFOC_r residual: {foc_r:.2e}) def pi_m_from_x(xx): w_, pd_, pr_, tau_ xx Dd_, Dr_ demands(pd_, pr_, p) return manufacturer_profit(pd_, w_, tau_, pr_, p) # 数值梯度检查 grad_numeric np.zeros(4) for i in range(4): xp x.copy(); xp[i] eps xm x.copy(); xm[i] - eps grad_numeric[i] (pi_m_from_x(xp) - pi_m_from_x(xm)) / (2*eps) print(fnumeric grad pi_m: {grad_numeric})这个脚本的价值在复现时最能体现。论文里的解析公式很长任何一位读者抄到代码里都可能漏一个偏导数项。把数值梯度打印出来与解析一阶条件对照哪一行公式抄错了立即显现。我自己的习惯是数值梯度残差超过1e-3就回去查公式不值得在这个步骤上抱有“差不多能跑就行”的侥幸心理。双渠道闭环供应链的决策优化做到最后真正检验模型的不是数学复杂度而是你能不能回答清楚三个问题退货补偿该定在什么区间、Stackelberg 主导方该让利多少、合作剩余怎么分才让双方都有动力维持闭环。这三件事在模型里分别对应s的外生设定、威胁点利润的选择、Nash 协商函数的约束。希望这套建模加代码的路径能帮你在自己的场景里少走一点弯路。提示复现时先跑基准参数确认输出符合直觉后再改参数改完参数务必重新跑第 6 章的两个验证脚本避免静默出错。本文还有配套的精品资源点击获取
返回列表