4. 网络构建实战:使用NetworkX构建供应链网络图
好,咱们直接动手。上一章我们把供应链金融的理论框架搭好了,这一章就来点实在的——用Python的NetworkX库,把那些抽象的企业、交易、账期,变成一张看得见摸得着的网络图。
我个人习惯,学任何网络建模,第一步不是写代码,而是先想清楚:节点是什么?边是什么? 供应链网络里,节点就是企业,边就是它们之间的交易关系。听起来简单,但实际项目中,我见过太多人一上来就画图,结果节点属性、边属性全乱套了。
4.1 环境准备与基础概念
先装好库。NetworkX是Python生态里最成熟的网络分析库,没有之一。
pip install networkx pandas matplotlib
导入的时候,我习惯这么写:
import networkx as nx
import pandas as pd
import matplotlib.pyplot as plt
NetworkX里最核心的两个东西:Graph(无向图)和DiGraph(有向图)。供应链金融里,交易是有方向的——A向B采购,钱从B流向A。所以,我们几乎只用DiGraph。
- 节点(Node):企业,每个节点有唯一ID
- 边(Edge):交易关系,有方向
- 属性(Attribute):挂在节点或边上的数据,比如企业规模、交易金额
4.2 构建基础供应链网络
咱们先造一个最简单的供应链:一个核心制造商,两家上游供应商,两家下游经销商。
G = nx.DiGraph()
# 添加节点
G.add_node('核心制造商')
G.add_node('供应商A')
G.add_node('供应商B')
G.add_node('经销商X')
G.add_node('经销商Y')
# 添加边(交易关系)
G.add_edge('供应商A', '核心制造商')
G.add_edge('供应商B', '核心制造商')
G.add_edge('核心制造商', '经销商X')
G.add_edge('核心制造商', '经销商Y')
嗯,这里要注意:边的方向代表物流方向。供应商把货发给核心制造商,所以边从供应商指向制造商。金融里常说的「反向保理」,其实就是顺着这个方向做融资。
画出来看看:
pos = nx.spring_layout(G, seed=42)
nx.draw(G, pos, with_labels=True, node_color='lightblue',
node_size=2000, font_size=12, arrows=True)
plt.title('基础供应链网络')
plt.show()
运行一下,你应该能看到五个节点和四条有向边。结构很简单,但这就是一切复杂网络的基础。
4.3 添加节点属性:企业规模与信用评级
光有节点名字不够。实际建模中,每个企业都有特征。比如企业规模(年营收)和信用评级(AAA到D)。
NetworkX添加节点属性有两种方式:
方式一:添加节点时直接带属性
G.add_node('核心制造商', 规模='大型', 营收=100, 信用评级='AAA')
G.add_node('供应商A', 规模='中型', 营收=20, 信用评级='A')
G.add_node('供应商B', 规模='小型', 营收=5, 信用评级='BBB')
G.add_node('经销商X', 规模='中型', 营收=15, 信用评级='A-')
G.add_node('经销商Y', 规模='小型', 营收=3, 信用评级='BB')
方式二:批量添加属性
我在项目中更常用这种方式,尤其是从数据库或Excel读数据时:
# 先添加节点
nodes = ['核心制造商', '供应商A', '供应商B', '经销商X', '经销商Y']
G.add_nodes_from(nodes)
# 再批量设置属性
node_attrs = {
'核心制造商': {'规模': '大型', '营收': 100, '信用评级': 'AAA'},
'供应商A': {'规模': '中型', '营收': 20, '信用评级': 'A'},
'供应商B': {'规模': '小型', '营收': 5, '信用评级': 'BBB'},
'经销商X': {'规模': '中型', '营收': 15, '信用评级': 'A-'},
'经销商Y': {'规模': '小型', '营收': 3, '信用评级': 'BB'}
}
nx.set_node_attributes(G, node_attrs)
检查一下属性是否添加成功:
print(G.nodes(data=True))
输出应该类似这样:
[('核心制造商', {'规模': '大型', '营收': 100, '信用评级': 'AAA'}),
('供应商A', {'规模': '中型', '营收': 20, '信用评级': 'A'}),
...]
4.4 添加边属性:交易金额与账期
边属性才是供应链金融建模的灵魂。交易金额决定了敞口大小,账期决定了资金占用时间。
# 添加边并带属性
G.add_edge('供应商A', '核心制造商', 交易金额=500, 账期=60)
G.add_edge('供应商B', '核心制造商', 交易金额=200, 账期=90)
G.add_edge('核心制造商', '经销商X', 交易金额=800, 账期=30)
G.add_edge('核心制造商', '经销商Y', 交易金额=300, 账期=45)
同样,也可以批量添加:
edge_attrs = {
('供应商A', '核心制造商'): {'交易金额': 500, '账期': 60},
('供应商B', '核心制造商'): {'交易金额': 200, '账期': 90},
('核心制造商', '经销商X'): {'交易金额': 800, '账期': 30},
('核心制造商', '经销商Y'): {'交易金额': 300, '账期': 45}
}
nx.set_edge_attributes(G, edge_attrs)
查看边属性:
print(G.edges(data=True))
4.5 可视化:让网络图说话
光有数据不够,得能看出来。我一般会根据节点属性调整颜色和大小,根据边属性调整粗细。
# 根据信用评级设置节点颜色
color_map = {'AAA': 'green', 'AA': 'lightgreen', 'A': 'yellowgreen',
'A-': 'gold', 'BBB': 'orange', 'BB': 'salmon', 'B': 'red'}
node_colors = [color_map[G.nodes[n]['信用评级']] for n in G.nodes()]
# 根据营收设置节点大小
node_sizes = [G.nodes[n]['营收'] * 30 for n in G.nodes()]
# 根据交易金额设置边宽度
edge_widths = [G.edges[e]['交易金额'] / 100 for e in G.edges()]
# 绘制
pos = nx.spring_layout(G, seed=42, k=2)
nx.draw(G, pos, with_labels=True, node_color=node_colors,
node_size=node_sizes, width=edge_widths,
font_size=10, arrows=True, arrowstyle='-|>')
plt.title('供应链金融网络(节点颜色=信用评级,大小=营收,边宽=交易金额)')
plt.show()
这张图一出来,信息量就大了。一眼能看出:核心制造商是最大的节点(营收高),供应商A的信用评级比供应商B好,核心制造商和经销商X的交易金额最大。
4.6 实战:从Excel构建完整网络
真实项目里,数据不会手动输入。我通常从Excel或数据库读。假设你有两个表:企业信息表和交易记录表。
# 读取企业信息
df_nodes = pd.read_excel('企业信息.xlsx')
# 假设列名:企业ID, 企业名称, 规模, 营收, 信用评级
# 读取交易记录
df_edges = pd.read_excel('交易记录.xlsx')
# 假设列名:买方ID, 卖方ID, 交易金额, 账期
# 构建网络
G = nx.DiGraph()
# 添加节点
for _, row in df_nodes.iterrows():
G.add_node(row['企业ID'],
名称=row['企业名称'],
规模=row['规模'],
营收=row['营收'],
信用评级=row['信用评级'])
# 添加边
for _, row in df_edges.iterrows():
G.add_edge(row['卖方ID'], row['买方ID'],
交易金额=row['交易金额'],
账期=row['账期'])
4.7 网络的基本统计量
网络建好了,先看看基本指标:
print(f"节点数: {G.number_of_nodes()}")
print(f"边数: {G.number_of_edges()}")
print(f"密度: {nx.density(G):.4f}")
print(f"是否有环: {nx.is_directed_acyclic_graph(G)}")
密度接近0说明网络稀疏,供应链网络通常如此——每个企业只跟少数上下游交易。如果有环,说明存在循环交易,这在供应链金融里要特别警惕,可能是虚假贸易。
我还习惯算一下每个节点的度:
for node in G.nodes():
in_deg = G.in_degree(node)
out_deg = G.out_degree(node)
print(f"{node}: 入度={in_deg}, 出度={out_deg}")
核心制造商的出度和入度都高,说明它既是主要买家也是主要卖家。这在供应链金融里,就是所谓的「核心企业」——银行做保理业务时最喜欢找这种节点。
4.8 本章小结
这一章我们干了三件事:
- 用NetworkX的DiGraph构建了有向供应链网络
- 给节点添加了企业规模和信用评级属性
- 给边添加了交易金额和账期属性
说白了,就是把一张Excel表变成了一个可计算的网络结构。下一章我们会在这个基础上,做更深入的分析——比如风险传播路径、核心企业识别、账期优化等等。
但别急,先把今天的内容跑一遍。代码不多,但每一步都值得亲手敲一遍。我在项目里吃过亏——数据量一大,属性挂错了位置,查了半天才发现是节点ID重复了。嗯,这些坑,你们提前知道就好。