3. 数据采集与预处理:数据源(ERP、发票、物流)、数据清洗、实体对齐、关系抽取
做供应链金融网络建模,有一件事我特别想强调——数据质量决定了模型的天花板。你算法再牛,喂进去一堆脏数据,出来的结果也是垃圾。这可不是开玩笑,我在项目里吃过不少亏。
这一章,咱们就聊聊数据怎么来、怎么洗、怎么对齐、怎么抽关系。说白了,就是把原始数据变成能喂给网络模型的干净食材。
3.1 数据源:ERP、发票、物流,三驾马车
供应链金融的数据源,我习惯分成三大类。你想想看,一个企业的经营状况,无非就是「买了什么、卖了什么、货到了没有」。
3.1.1 ERP 系统数据
ERP 是核心。里面藏着采购订单、销售订单、库存台账、应付应收账龄。我个人习惯先拉 采购订单 + 应付账款 和 销售订单 + 应收账款 这两张表。
嗯,这里要注意。不同企业的 ERP 字段命名千奇百怪。有的叫「供应商编码」,有的叫「供货方编号」。我建议你第一步先做字段映射表,别上来就写代码。
3.1.2 发票数据
发票是金融级别的凭证。它的可信度比 ERP 内部数据高一个量级。为什么?因为发票要过税务局系统,造假成本极高。
我在项目中遇到过,有些企业 ERP 里显示欠款 500 万,但拉出发票一看,实际开票金额只有 300 万。差额去哪了?可能是未开票收入,也可能是虚增库存。发票数据能帮你交叉验证。
| 数据源 | 核心字段 | 可信度 | 更新频率 |
|---|---|---|---|
| ERP | 订单、库存、账龄 | 中 | 实时/每日 |
| 发票 | 发票号、金额、税号、商品名 | 高 | 开票时 |
| 物流 | 运单号、发货地、签收时间 | 中高 | 实时 |
3.1.3 物流数据
物流数据是「实物流」的映射。没有物流佐证的交易,说白了就是空转。我见过不少供应链金融暴雷案例,核心问题就是「钱出去了,货没动」。
物流数据通常来自 WMS 系统或第三方物流平台。关键看 发货单、签收单、在途状态。时间戳尤其重要——发货时间和签收时间之间的差值,就是资金占压周期。
3.2 数据清洗:别让脏数据毁了模型
数据清洗听着枯燥,但它是整个流程里最花时间的环节。我一般会花 60% 的时间在清洗上,40% 的时间建模。你想想看,如果数据里有 5% 的错误,网络结构可能就完全走样了。
3.2.1 常见脏数据类型
- 缺失值: 比如供应商ID为空、金额字段为 null。我建议先看缺失比例,超过 30% 的字段直接考虑剔除。
- 重复记录: 同一个订单号出现多次。可能是系统重推,也可能是人工补录。我曾经遇到一个客户,ERP 里同一个采购单录了 7 遍。
- 异常值: 金额为负数、日期为 1900 年、数量为 0。这些明显是录入错误。
- 格式不一致: 日期有的写「2024-01-01」,有的写「2024/01/01」,还有的写「2024年1月1日」。
3.2.2 清洗流程示例
我习惯用 Python 的 pandas 做清洗。给你看一段我常用的代码骨架:
import pandas as pd
import numpy as np
# 加载数据
df_erp = pd.read_csv('erp_orders.csv')
# 1. 去重
df_erp = df_erp.drop_duplicates(subset=['order_id'])
# 2. 处理缺失值
df_erp['supplier_id'].fillna('UNKNOWN', inplace=True)
df_erp['amount'].fillna(0, inplace=True)
# 3. 异常值过滤
df_erp = df_erp[(df_erp['amount'] > 0) & (df_erp['order_date'] > '2020-01-01')]
# 4. 统一日期格式
df_erp['order_date'] = pd.to_datetime(df_erp['order_date'], errors='coerce')
print(f"清洗后数据量: {len(df_erp)} 条")
3.3 实体对齐:把「同一个企业」找出来
实体对齐是供应链金融网络建模里最头疼的问题之一。为什么?因为同一个企业在不同数据源里的名字可能完全不一样。
举个例子:
ERP 里叫「深圳市华为技术有限公司」
发票里叫「华为技术有限公司」
物流单里叫「华为」
这三个名字,你作为人一眼能看出来是同一家。但机器不会。如果不做对齐,网络里就会出现三个节点,关系全乱套了。
3.3.1 对齐策略
我一般分三步走:
- 精确匹配: 先用统一社会信用代码、税号、工商注册号做精确匹配。这是最靠谱的。
- 模糊匹配: 没有唯一标识的,用公司名称做字符串相似度匹配。我常用
fuzzywuzzy库,设置阈值 85 分以上算匹配。 - 人工校验: 模糊匹配的结果,抽 10% 做人工复核。别全信算法。
3.4 关系抽取:构建网络边的核心
实体对齐搞定了节点,关系抽取就是搞定边。供应链金融网络里的关系,我归纳为三类:
- 交易关系: A 向 B 采购了商品,产生了应付/应收
- 担保关系: A 为 B 的融资提供了担保
- 股权关系: A 持有 B 的股份
关系抽取的核心逻辑,就是从非结构化或半结构化的数据里,提取出「主体-谓词-客体」三元组。
3.4.1 从发票抽取交易关系
发票数据里,关系是显式的。一张发票上,购买方和销售方就是一条交易边。我一般这样处理:
# 发票关系抽取示例
df_invoice = pd.read_csv('invoices.csv')
# 提取交易关系三元组
relations = []
for _, row in df_invoice.iterrows():
relations.append({
'source': row['buyer_tax_id'], # 购买方税号
'target': row['seller_tax_id'], # 销售方税号
'type': 'trade',
'amount': row['invoice_amount'],
'date': row['invoice_date']
})
df_relations = pd.DataFrame(relations)
print(f"共抽取 {len(df_relations)} 条交易关系")
3.4.2 从合同文本抽取担保关系
担保关系通常藏在合同文本里。这时候需要用到 NLP 技术。我习惯用正则表达式先做一轮粗筛,再配合命名实体识别(NER)做精抽。
举个例子,合同里出现「甲方为乙方提供连带责任保证」,那「甲方」和「乙方」之间就有一条担保边。
3.5 本章知识体系总览
下面这张图,是我梳理的数据采集与预处理全流程。你可以把它当作操作手册来用。
这张图从左到右,从上到下,就是咱们这一章的核心脉络。数据从三个源头进来,经过清洗、对齐、抽取,最终变成结构化的网络数据。
好了,数据采集与预处理就聊到这儿。下一章咱们会基于这些干净数据,开始构建真正的供应链金融网络模型。到时候你会发现,前面这些脏活累活,全都值了。
公众号:蓝海资料掘金营,微信deep3321