3. 数据采集与预处理:数据源(ERP、发票、物流)、数据清洗、实体对齐、关系抽取

做供应链金融网络建模,有一件事我特别想强调——数据质量决定了模型的天花板。你算法再牛,喂进去一堆脏数据,出来的结果也是垃圾。这可不是开玩笑,我在项目里吃过不少亏。

这一章,咱们就聊聊数据怎么来、怎么洗、怎么对齐、怎么抽关系。说白了,就是把原始数据变成能喂给网络模型的干净食材。

3.1 数据源:ERP、发票、物流,三驾马车

供应链金融的数据源,我习惯分成三大类。你想想看,一个企业的经营状况,无非就是「买了什么、卖了什么、货到了没有」。

3.1.1 ERP 系统数据

ERP 是核心。里面藏着采购订单、销售订单、库存台账、应付应收账龄。我个人习惯先拉 采购订单 + 应付账款销售订单 + 应收账款 这两张表。

关键字段: 订单号、供应商ID、客户ID、商品编码、数量、单价、金额、订单日期、交货日期、付款条件。

嗯,这里要注意。不同企业的 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 对齐策略

我一般分三步走:

  1. 精确匹配: 先用统一社会信用代码、税号、工商注册号做精确匹配。这是最靠谱的。
  2. 模糊匹配: 没有唯一标识的,用公司名称做字符串相似度匹配。我常用 fuzzywuzzy 库,设置阈值 85 分以上算匹配。
  3. 人工校验: 模糊匹配的结果,抽 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 本章知识体系总览

下面这张图,是我梳理的数据采集与预处理全流程。你可以把它当作操作手册来用。

数据采集与预处理流程 ERP 数据 订单/库存/账龄 发票数据 金额/税号/商品 物流数据 运单/签收/在途 数据清洗 缺失值处理 → 去重 → 异常值过滤 → 格式统一 实体对齐 精确匹配(税号) → 模糊匹配(名称) → 人工校验 关系抽取 交易关系 | 担保关系 | 股权关系 输出:实体-关系三元组

这张图从左到右,从上到下,就是咱们这一章的核心脉络。数据从三个源头进来,经过清洗、对齐、抽取,最终变成结构化的网络数据。

我的经验: 别想着一步到位。先跑通一个小样本(比如 1000 条数据),验证流程没问题了,再全量跑。否则你调试一次要等半天,心态容易崩。

好了,数据采集与预处理就聊到这儿。下一章咱们会基于这些干净数据,开始构建真正的供应链金融网络模型。到时候你会发现,前面这些脏活累活,全都值了。


公众号:蓝海资料掘金营,微信deep3321