2026/9/20 21:01:23

供应链断裂与重构测度:基于网络分析的Python量化实战

供应链断裂与重构测度:基于网络分析的Python量化实战 简介一份面向经济学研究者、供应链分析人员及数据科学初学者的Python代码包用于复现丁浩员等发表于《经济研究》2024年第8期的跨国供应链断裂与重构变量测度方法。包体以FactSet Revere全球供应链数据库为数据源完整覆盖断裂Break、恢复Recover、转移Transfer三个核心指标的构建逻辑并自带数据预处理、供应链关系筛选、时间顺序调整、结果输出等环节的完整实现读者可基于示例数据快速跑通全链路再替换为自己的数据开展实证分析。压缩包共25个文件包含8个Python脚本对应数据清洗、指标计算、结果分析与可视化等环节8个Excel文件存放输入样例和输出结果另有3个文本说明、2个HTML交互式报告、1个PNG图表及README文档整体大小仅1.27MB结构紧凑易上手。已有860人学习尤其适合正在研究供应链风险、企业间依赖关系或跨国生产网络的经济学学生与科研工作者参考复用。1. 先说清楚供应链断裂与重构到底在测度什么这几年做供应链管理的人普遍被一个问题反复折磨——客户电话打来说“料断了两周”或者采购半夜发消息说“某核心物料供应商爆仓了”。断裂不再是偶发事件而是常态化风险。但真正让我开始认真研究“测度”这件事的是我发现自己根本没有一个量化指标能回答以下三个问题断得有多深多久能恢复恢复之后供应链跟原来还一样吗“供应链断裂与重构测度”这个方向就是用来回答上述问题的。它本质上是一个量化体系边界上你要把一个原本靠Excel和PPT汇报的风险事件变成一组可以被持续跟踪、对比、预警的数字技术上它依赖网络分析、图计算和统计建模落到实操层就是用Python做网络构建、拆解和指标计算。“供应链”不是一条链而是一张网供应商、制造商、分销商、客户之间是互相交织的关系一个环节断裂可能会顺着网络传导到很远的地方。测度这张网的“断裂风险”和“重构能力”比盯单个供应商的库存要可靠得多。这篇内容适合三类人一类是甲方企业内部做供应链风险、采购数字化的人需要给管理层交付“韧性看板”一类是做物流与供应链研究的同学写论文做案例需要可复现的测度代码还有一类是刚入行、想把供应链管理和数据分析结合的从业者。我会把测度框架、核心指标、一套可直接改的Python代码以及我在实践中踩过的坑一次性讲清楚。2. 整体设计思路为什么是“网络视角”而非“链路视角”2.1 从一次断供事件说起拆出测度的本质假设你是一家做智能硬件的公司核心物料是某种定制芯片供应商A供货占你总需求的70%。某天供应商A工厂因火灾停产这个事件会沿着你的供应链网络一路传导A停货 - 成品组装线上产能骤降到三成 - 渠道端欠货 - 客户流失。传统的“链路视角”是把供应关系画成一条直线A - 你 - 客户你能看到的只有“供应中断”和“销售损失”两个结果。但如果切换到“网络视角”你可能会发现虽然A断供但你还有备选的供应商B和CA的物料要通过物流商D承运而D同时也在给B供货客户E和F对交期敏感度不同G则可以接受分批交付。这时候断裂的影响就取决于网络的冗余、路径的替代性、节点的集中度——这就是“断裂测度”的核心逻辑所在。所以我把整个测度体系拆成三层第一层是“生存度”即断供发生后企业业务能维持到什么水平典型指标是“最长可维持天数”和“产能损失率”第二层是“恢复速度”即网络在多长时间内找到替代路径典型指标是“重构周期”和“替代路径启用时间”第三层是“结构状态”即重构之后的网络跟断裂之前相比发生了多大变化典型指标是“网络相似度”和“中心度迁移值”。2.2 三个关键维度暴露度、冲击强度、恢复力把这三层再浓缩就会得到供应链测度的三个支柱维暴露度你有多容易被某一次断裂伤到。它是关于“结构集中度”的函数比如你的供应源是否单一、关键节点是否有替代、网络是否存在“单点桥”结构。简单说暴露度回答的是“如果这堵墙倒了有多少东西压在下面”。冲击强度断裂发生以后实际的业务损失有多大。这要结合网络传导来计算典型的做法是模拟节点失效然后观察最大连通子图的变化、可用路径数量的跌幅、供应链总成本的上浮幅度。恢复力你重新稳定下来的能力和速度。不仅仅是“找到新供应商”那一下还包括重路由是否代价巨大、是否出现新的瓶颈、重构后的网络是否比原来更脆弱。代码实现时这三个维度对应了不同的量化方式。网络层面对暴露度用中心性和连通性计算对冲击强度用“删边/删点再计算网络指标”的差分方式求解对恢复力则模拟“重连边”之后指标回到什么水平。整个设计思路就是把管理问题转化成网络问题把网络问题转化成可计算的数学指标。3. 数据准备与指标计算这一步做不好后面全是废的3.1 数据从哪里来图数据的本质做测度之前必须想明白一个事你手里的业务数据能不能构成一张“图”图网络的基本单位是“节点”和“边”。节点可以是供应商、工厂、仓库、客户边可以是采购订单关系、物流运输关系、信息协同关系。在实际项目里我用到过几种最常见的数据来源采购台账记录了采购订单的供应商编码、物料编码、金额、交期、品质合格率这是构建“供应商-物料”关系的基础数据。物流运单包含发货地、收货地、运输方式、时效、异常事件这是构建“节点-节点”物理连接的数据。合同关系和资质信息可以告诉你是否是长期战略合作、是否有备用产地这在重构测度里是判断“能否快速激活”的依据。ERP里的BOM物料清单告诉你成品由哪些部件构成是拆解传导路径的关键。这里有个非常容易犯的错认为“Excel能导出来就能直接算”。实际不是。图计算要求数据结构是干净的三元组起点、终点、关系强度。如果你的采购台账里供应商名称存在多种写法“深圳华科电子”和“深圳华科电子有限公司”合并之后会凭空多出一堆假节点那么这个图的“密度”和“路径长度”指标就会失真。所以在做测度之前先用30分钟做一个“实体对齐”的清洗工作。对供应商、物料、工厂三类核心主体做标准化映射。我的做法是提取名称的拼音首字母和统一社会信用代码后6位用多维匹配形成一个唯一ID表。3.2 核心指标的口径定义建图之后关键的测度指标要在一开始就定义清楚口径否则后面会反复改代码。我常用的几个核心指标如下网络节点数N和边数E这是基础但注意如果你是多层供应链网络节点要区分层级比如把节点的“type”属性设为supplier / manufacturer / distributor / customer。网络密度E / (N*(N-1))。密度越高网络越冗余理论上断裂的传导路径越多但不一定代表越强韧因为密度高可能意味着共担风险的多源供应也少。平均最短路径长度所有节点对之间最短距离的平均值。断裂后这个值通常会增加因为它反映了绕路的代价。最大连通子图规模LCC删除某个节点/边之后网络中最大的连通组包含多少节点。这是衡量“断裂严重程度”最直观的指标后面代码的核心部分就在这里。节点中心性度中心性、介数中心性识别哪些节点是“枢纽”。介数中心性高的节点一旦断裂会极大影响全网络的流通效率。恢复力指标模拟“重连边”之后LCC规模恢复到原规模的百分比以及平均路径长度恢复的百分比。其中最重要的是LCC因为它同时体现了深度和广度。一个核心工厂断裂如果LCC从100个节点掉到45个说明接近一半的网络被孤立了这个冲击就是很剧烈的。4. Python代码实现一套能直接改成自己能用的断裂与重构测度脚本4.1 环境准备与数据模拟我假设你已经安装了Python 3.8并且有pandas、networkx、matplotlib、numpy这几个库。如果没有直接pip install pandas networkx matplotlib numpy但真正的生产环境里我推荐用networkx做原型、用igraph或graph-tool处理超大图。这里为演示方便用networkx它的API友好、可视化方便适合快速验证思路。我们先模拟一个供应链网络。实际项目中的数据往往涉密但结构大致如下20个供应商、5个制造商、8个分销商、15个客户。为了更真实我会让节点之间按“层级优先”连边同时保持一定比例的跨层直连模拟现实中的VMI供应商管理库存或者JIT准时制供货关系。import networkx as nx import numpy as np import pandas as pd import matplotlib.pyplot as plt from itertools import combinations np.random.seed(42) # 1. 生成节点 suppliers [fS{i} for i in range(1, 21)] manufacturers [fM{i} for i in range(1, 6)] distributors [fD{i} for i in range(1, 9)] customers [fC{i} for i in range(1, 16)] G nx.DiGraph() for node in suppliers manufacturers distributors customers: G.add_node(node, typenode[0]) # 2. 按照层级关系连边 # 供应商 - 制造商 for s in suppliers: for m in np.random.choice(manufacturers, sizenp.random.randint(1, 4), replaceFalse): G.add_edge(s, m, weightnp.random.uniform(0.5, 1.0)) # 制造商 - 分销商 for m in manufacturers: for d in np.random.choice(distributors, sizenp.random.randint(2, 5), replaceFalse): G.add_edge(m, d, weightnp.random.uniform(0.5, 1.0)) # 分销商 - 客户 for d in distributors: for c in np.random.choice(customers, sizenp.random.randint(3, 8), replaceFalse): G.add_edge(d, c, weightnp.random.uniform(0.5, 1.0)) # 少量跨层直连制造商直供客户 for m in manufacturers: for c in np.random.choice(customers, size2, replaceFalse): G.add_edge(m, c, weightnp.random.uniform(0.5, 1.0)) print(节点数:, G.number_of_nodes(), 边数:, G.number_of_edges())这里的关键是“随机连边不代表真实”但代码逻辑是通用的。真实场景中你要把采购台账里的每条订单关系merge进来而不是随机生成。4.2 断裂冲击模拟节点失效后的网络级联测度“断裂”最直接的办法是删除节点再看指标变化。这里我实现三个层次随机故障随机删点、定向打击删除度中心性最高的节点、级联失效删除一个节点后如果产生孤立的下游节点则继续删除形成一个连锁反应。def calc_lcc_ratio(G): # 计算最大弱连通子图的规模占全图节点比例 if G.number_of_nodes() 0: return 0.0 largest max(nx.weakly_connected_components(G), keylen) return len(largest) / G.number_of_nodes() def remove_and_measure(G, node): H G.copy() H.remove_node(node) # 如果被删除节点的上游或下游出现孤立节点也一并删掉级联效应 cascaded [] for n in list(H.nodes()): if H.degree(n) 0: cascaded.append(n) H.remove_nodes_from(cascaded) return calc_lcc_ratio(H), len(cascaded), H # 找中心性最高的节点 betweenness nx.betweenness_centrality(G) top_node max(betweenness, keybetweenness.get) print(介数中心性最高的节点:, top_node, 值:, round(betweenness[top_node], 4)) lcc_after, cascade_count, H remove_and_measure(G, top_node) print(原始LCC占比:, round(calc_lcc_ratio(G), 4)) print(删除后LCC占比:, round(lcc_after, 4)) print(级联失效节点数:, cascade_count)跑完这段你会直观看到删一个节点可能导致网络残废。在我的模拟数据里删除介数中心性最高的节点后有接近30%的节点被级联隔离。这就是“断点”应该预警的位置——断点不是看谁订单金额大而是看谁在结构上扮演着“桥梁”角色。4.3 重构测度模拟重建供应路径后的网络恢复重构测度比断裂更进一层。我的思路是把“断掉”的节点从网络中移除然后模拟一个可行的重建策略——为受影响的客户寻找替代供应商也就是“重连边”。具体做法是找到原网络中客户节点断开的目标Supplier然后从其它functioning的Supplier中寻找同类型替代。# 记录受影响的供应商-客户关系 def reconstruct_network(G, failed_nodes): H G.copy() affected_customers set() # 移除失效节点 H.remove_nodes_from(failed_nodes) for n in failed_nodes: if n in G: for succ in G.successors(n): if H.has_node(succ) and H.out_degree(succ) 0: affected_customers.add(succ) # 为受影响的客户重连新的供应商从仍然活跃的supplier中找 active_suppliers [n for n in H.nodes() if n.startswith(S)] new_edges 0 for c in affected_customers: if len(active_suppliers) 0: new_supplier np.random.choice(active_suppliers) H.add_edge(new_supplier, c, weight0.8) new_edges 1 return H, new_edges # 模拟两个工厂断裂 - 重构 failed [M1, M3] H_rebuilt, new_edges reconstruct_network(G, failed) metrics_before { LCC_ratio: calc_lcc_ratio(G), avg_path: nx.average_shortest_path_length(G, weightweight) } metrics_after { LCC_ratio: calc_lcc_ratio(H_rebuilt), avg_path: nx.average_shortest_path_length(H_rebuilt, weightweight) } print(重构前 LCC占比:, round(metrics_before[LCC_ratio], 4), 平均路径长度:, round(metrics_before[avg_path], 4)) print(重构后 LCC占比:, round(metrics_after[LCC_ratio], 4), 平均路径长度:, round(metrics_after[avg_path], 4)) print(新增替代连接数:, new_edges)这段代码会让你看到重构的核心逻辑即便节点数量恢复了平均路径长度也通常不会再回到原来的水平因为“重连”往往不是最优的拓扑而是“能用就行”的应急方案。这也就是为什么重构测度一定要看“结构是否回归”不能只看“客户订单是否恢复”。4.4 可视化让管理层一眼看懂网络健康度数据指标是给分析师看的但汇报的时候还是需要用图说话。我习惯把断裂前、断裂后、重构后三张网络图并排输出节点颜色表示层级、节点大小表示介数中心性、断开的路径用虚线标出。def draw_network(G, title, ax): pos nx.spring_layout(G, seed42, k0.8) node_colors {S: #2E86AB, M: #A23B72, D: #F18F01, C: #73AB84} colors [node_colors[n[0]] for n in G.nodes()] sizes [400 3000 * betweenness.get(n, 0) for n in G.nodes()] nx.draw_networkx(G, pos, axax, node_colorcolors, node_sizesizes, font_size6, with_labelsFalse, arrowsTrue, edge_colorgray) ax.set_title(title) ax.axis(off) fig, axes plt.subplots(1, 3, figsize(18, 6)) draw_network(G, 原始网络, axes[0]) draw_network(H, 断裂后网络, axes[1]) draw_network(H_rebuilt, 重构后网络, axes[2]) plt.tight_layout() plt.savefig(supply_chain_network_reconstruction.png, dpi150) plt.show()注意NetworkX画大图很慢超过500个节点会比较吃力这时候可以用graphviz的布局替代spring_layout或者干脆只导出节点坐标表到Gephi里再出图。汇报场景下重点是让管理层看到“图出现了明显的空洞”和“空洞被填上但有新瓶颈”这两个信息。5. 实操中的常见坑与排查技巧5.1 指标为什么会“虚高”很多初做供应链测度的人会在报告里写“我们的LCC占比是0.98网络很健康”。但这个数字很可能毫无意义。原因是如果没有按层级分拆去计算而是全网络混在一起那么大量客户节点即使断了也依然和其他客户在同一个松散连通分量里LCC降不下来。解法是按层级做条件切片例如分别计算“供应商子图”“制造商-分销商子图”。我一般会额外计算一个指标关键路径上的LCC占比——只保留介数中心性Top20的节点切断之后再看这个“主干网络”的碎片化程度。这样报出来的数字才是管理层真正关心的“核心业务是否中断”。5.2 数据稀疏时怎么办刚起步的公司往往没有完整的图数据只有几个重点客户和供应商的订单记录。这时候强行构建全网络图很多节点只有一条边算出来的中心性几乎是随机噪声。我的经验是先做“子网络测度”选取Top30的供应商和Top10的客户构建一个局部网络只测度这个局部网络内的断裂和重构。虽然覆盖不全但至少能反映核心业务关系。另外可以给网络数据打标签区分“实测边”和“推断边”推断边用于补全但计算指标时建议对两类边分别做敏感性分析。5.3 重构测度的时间窗口重构不是瞬间完成的。现实中找到一个替代供应商、完成认证、打样、小批量供货可能需要8到16周。如果忽略时间维度重构测度就会把“已建立连接”当成“已经恢复”但产能爬坡还没完成。所以代码里的重构模拟应该加入时间步参数按“第1周恢复20%产能、第4周恢复70%产能”这种阶梯式方式计算。在指标上可以增加“重构半周期”即产能恢复到50%所需的时间。我建议在代码里把“重构”相关的边都增加一个recovery_time属性然后用时间衰减函数折算有效供应能力。这个方法在汇报时也特别有用——管理层不是只想知道“能不能重建”而是“多久能重建完”。6. 最后再分享一个我自己摸出来的扩展用法我在做完上面的测度框架之后发现它不只是用来做“事后复盘”的。如果你把历史正常时期的网络指标连续计算形成基线然后对每一天的新数据做实时测算就能得到一个“网络健康指数”的时序曲线。当某个指标的滑落超过2个标准差时基本意味着供应链正在进入“断裂前兆”状态——这时候介入调整往往还能避免真正的断供。这个方向还可以继续扩展成压力测试工具随机删掉多个节点组合计算网络在最坏情况下的剩余承载力再把“备选供应商清单”输入进去看哪个组合方案重构后的网络指标最优。这比拍脑袋决定选哪家备用供应商要科学得多。说到底供应链断裂与重构测度这件事代码只占四成功夫另外六成在业务理解和数据结构设计上。但代码是那个让一切从“拍脑袋”变成“可复现”的支点。如果你的网络数据已经搭好跑通上面的流程并不会花太多时间真正花时间的是想清楚你要回答的业务问题然后用数字说服别人。本文还有配套的精品资源点击获取