第4章:网络数据获取——公开数据源、数据清洗与预处理、网络构建实战
各位同学,今天咱们聊聊金融网络仿真里最基础、也最磨人的一步——数据获取与清洗。
说实话,我见过太多项目,模型建得花里胡哨,结果数据源一塌糊涂,最后全白干。你想想看,网络结构再漂亮,输入的是垃圾数据,输出能靠谱吗?
这一章,我就带大家走一遍完整流程:从央行、BIS这些公开数据源捞数据,到清洗预处理,最后亲手搭出一个金融网络。
4.1 公开数据源:央行与BIS
做金融网络分析,数据源就那么几个靠谱的。我个人最常用的是两个:
- 中国人民银行(PBOC):发布银行间市场数据、同业拆借利率、资产负债表等。我习惯去“调查统计司”栏目扒数据。
- 国际清算银行(BIS):全球银行间跨境头寸数据、衍生品统计。BIS的“Locational Banking Statistics”是构建国际金融网络的宝藏。
嗯,这里要注意:BIS的数据是季度更新的,而且有3个月左右的滞后期。别指望拿它做实时风控。
核心数据字段:
- 报告国(Reporting Country)
- 对手国(Counterparty Country)
- 资产/负债类型(Loans, Deposits, Derivatives)
- 金额(百万美元)
- 时间戳(季度末)
4.2 数据清洗与预处理
数据拿到手,别急着用。我曾经有一次直接从BIS下载CSV,里面居然混着法文注释和空行,跑脚本直接报错。从那以后,我养成了固定清洗流程。
4.2.1 常见脏数据
| 问题类型 | 表现 | 处理方法 |
|---|---|---|
| 缺失值 | 某些国家间无交易记录 | 填充0或插值(看场景) |
| 重复行 | 同一笔交易出现两次 | 按时间戳+对手方去重 |
| 单位不一致 | 有的用百万,有的用十亿 | 统一转为百万美元 |
| 编码问题 | 国家名用中文、英文混排 | 统一ISO 3166-1 alpha-2代码 |
避坑指南:我曾经在处理BIS数据时,发现日本和英国之间的交易额突然暴增。排查了半天,原来是某行把“JPY”和“GBP”的单位搞混了。所以,清洗时一定要做单位校验。
4.2.2 清洗代码示例(Python)
import pandas as pd
import numpy as np
# 读取原始数据
df = pd.read_csv('bis_data_raw.csv', encoding='utf-8')
# 1. 去除空行和注释行
df = df.dropna(how='all')
df = df[~df['country'].str.startswith('#', na=False)]
# 2. 统一国家代码
country_map = {'中国': 'CN', '美国': 'US', '日本': 'JP'}
df['country_code'] = df['country'].map(country_map)
# 3. 金额单位统一(假设原始是十亿,转百万)
df['amount_million'] = df['amount_billion'] * 1000
# 4. 去重
df = df.drop_duplicates(subset=['reporting_country', 'counterparty_country', 'quarter'])
# 5. 缺失值处理:无交易填0
df['amount_million'] = df['amount_million'].fillna(0)
print(f"清洗后数据量:{len(df)} 行")
4.3 网络构建实战
数据洗干净了,接下来就是搭网络。说白了,就是把国家/银行看成节点,交易金额看成边的权重。
4.3.1 邻接矩阵构建
我习惯用NetworkX库。先建一个有向图,方向从“报告国”指向“对手国”,权重就是交易金额。
import networkx as nx
# 创建有向图
G = nx.DiGraph()
# 添加边(从清洗后的数据)
for _, row in df.iterrows():
G.add_edge(
row['reporting_country'],
row['counterparty_country'],
weight=row['amount_million']
)
# 查看网络基本信息
print(f"节点数:{G.number_of_nodes()}")
print(f"边数:{G.number_of_edges()}")
4.3.2 网络可视化
光看数字不过瘾,咱们画出来。下面这张SVG图展示了核心逻辑:
4.3.3 网络指标计算
网络搭好了,咱们算几个关键指标。我个人最关注的是“度中心性”和“中介中心性”——前者看谁交易多,后者看谁控制着资金流。
# 计算度中心性(入度+出度)
degree_centrality = nx.degree_centrality(G)
# 计算中介中心性
betweenness_centrality = nx.betweenness_centrality(G, weight='weight')
# 输出Top 3
top_degree = sorted(degree_centrality.items(), key=lambda x: x[1], reverse=True)[:3]
top_between = sorted(betweenness_centrality.items(), key=lambda x: x[1], reverse=True)[:3]
print("度中心性Top3:")
for node, val in top_degree:
print(f" {node}: {val:.4f}")
print("中介中心性Top3:")
for node, val in top_between:
print(f" {node}: {val:.4f}")
注意:中介中心性在有向加权图上计算量很大。我当年用1000个节点的网络跑过一次,等了半小时才出结果。建议先做子图采样,或者用近似算法。
4.4 实战小结
这一章咱们走完了从数据到网络的完整链路。你想想看,其实核心就三步:
- 找数据:央行、BIS,别去野鸡网站扒。
- 洗数据:缺失、重复、单位、编码,一个都不能放过。
- 建网络:用NetworkX搭图,算指标,画出来看看。
嗯,最后提醒一句:公开数据虽然方便,但精度有限。真要拿来做风控,还得结合内部交易数据。我当年在银行做项目时,就是先用公开数据搭个框架,再拿内部数据去校准,效果还不错。
公众号:蓝海数据掘金营,微信deep3321