4. 数据清洗与预处理:数据去重、缺失值处理、文本标准化、实体对齐
说实话,产业链数据刚拿到手的时候,那叫一个「脏」。我做了这么多年数据工作,见过最离谱的一次——同一个企业名称在表格里出现了七种写法,什么「华为技术有限公司」、「华为技术」、「HUAWEI」、「华为(深圳)」……你想想看,这要是直接拿去构建图谱,出来的东西能看吗?
所以,数据清洗和预处理这一步,我把它叫做「地基工程」。地基没打好,后面所有分析都是空中楼阁。咱们这一节,就把四个核心环节掰开揉碎讲清楚。
4.1 数据去重:别让重复数据毁了你的图谱
数据去重,听起来简单吧?不就是删掉重复行嘛。但产业链数据里的「重复」,远比你想象的复杂。
- 完全重复:两行数据一模一样,直接删掉一行。
- 关键字段重复:比如企业名称相同,但其他字段有细微差异。
- 语义重复:「小米科技」和「小米科技有限公司」其实是同一家,但字符串不同。
我在项目中遇到过最头疼的就是第三种。当时处理一个汽车产业链的数据集,光「比亚迪」就有「比亚迪股份有限公司」、「比亚迪汽车」、「BYD」三种写法。你直接用 drop_duplicates() 肯定不行,得用模糊匹配。
我个人习惯用 fuzzywuzzy 这个库,配合一个相似度阈值来做去重。举个例子:
from fuzzywuzzy import fuzz
def dedup_by_name(df, threshold=85):
"""基于名称相似度去重"""
unique_names = []
dup_indices = []
for idx, name in enumerate(df['company_name']):
is_dup = False
for uniq in unique_names:
score = fuzz.ratio(name, uniq)
if score >= threshold:
is_dup = True
dup_indices.append(idx)
break
if not is_dup:
unique_names.append(name)
return df.drop(index=dup_indices)
4.2 缺失值处理:别让「空」变成「坑」
产业链数据里,缺失值太常见了。尤其是上下游关系、产能数据这些字段,经常是空的。怎么处理?我一般分三步走。
4.2.1 先诊断,再下药
别一上来就填值。先看看缺失率有多高,缺失模式是什么样的。
# 快速查看缺失情况
import missingno as msno
msno.matrix(df)
这张图能告诉你:哪些列缺失严重,哪些行是「重灾区」。如果一列缺失超过70%,我建议直接扔掉——硬填进去也是噪声。
4.2.2 分类处理策略
| 字段类型 | 缺失率 | 推荐处理方式 |
|---|---|---|
| 企业名称 | <5% | 删除该行 |
| 注册资本 | 10%-30% | 用行业均值填充 |
| 上下游关系 | 30%-50% | 用知识图谱推理补全 |
| 产能数据 | >50% | 标记为「未知」,单独处理 |
4.3 文本标准化:把「方言」翻译成「普通话」
产业链数据来自不同渠道,文本格式五花八门。有的用全角字符,有的用半角;有的写「深圳市」,有的写「深圳」;有的写「2023年」,有的写「2023-01-01」……
文本标准化的核心就一句话:统一表达,消除歧义。
4.3.1 常见的标准化操作
- 大小写统一:所有英文转大写或小写
- 全半角转换:全角数字、字母转半角
- 地名标准化:「北京」vs「北京市」→ 统一为「北京市」
- 日期格式化:统一为 YYYY-MM-DD
- 企业后缀统一:「有限公司」vs「有限责任公司」→ 统一处理
import re
def standardize_company_name(name):
"""企业名称标准化"""
# 去除多余空格
name = re.sub(r'\s+', '', name)
# 统一后缀
name = name.replace('有限责任公司', '有限公司')
# 去除括号内的冗余信息
name = re.sub(r'[((][^))]*[))]', '', name)
return name.strip()
4.4 实体对齐:把「散装」的实体「拼」起来
实体对齐,说白了就是判断两个实体是不是同一个。比如「阿里巴巴」和「Alibaba Group」是不是一家?「腾讯云」和「腾讯云计算」是不是同一个业务实体?
这是产业链图谱构建里最考验功力的环节。我一般用三层匹配策略:
4.4.1 精确匹配
完全相同的字符串,直接对齐。这个最简单,但覆盖不了多少情况。
4.4.2 模糊匹配
用编辑距离、Jaccard相似度、TF-IDF向量余弦相似度等方法。我比较喜欢用 rapidfuzz,速度比 fuzzywuzzy 快很多。
from rapidfuzz import fuzz
def align_entities(source_name, target_names, threshold=80):
"""实体对齐:找到最相似的候选"""
best_score = 0
best_match = None
for target in target_names:
score = fuzz.token_sort_ratio(source_name, target)
if score > best_score:
best_score = score
best_match = target
if best_score >= threshold:
return best_match
return None
4.4.3 基于知识库的推理对齐
当模糊匹配也搞不定时,就得借助外部知识库了。比如用天眼查、企查查的API,或者用Wikidata的SPARQL查询。我记得有一次处理半导体产业链数据,「中芯国际」和「SMIC」在文本上相似度只有60多分,但通过知识库一查,发现是同一家,这才对齐成功。
- 先精确,再模糊,最后推理
- 保留对齐置信度,低置信度的标记为「待人工审核」
- 建立实体映射表,方便后续增量更新
4.5 本章知识体系总览
下面这张图,是我自己梳理的数据清洗与预处理全流程。你看一遍,基本就知道每一步该做什么了。
嗯,这张图基本把咱们这一章的核心逻辑串起来了。你仔细看,四个模块是并行的,但顺序上我建议先做去重和缺失值处理,再做标准化,最后做实体对齐。为什么?因为去重和缺失值处理能减少数据量,后面的步骤就轻松多了。
好了,数据清洗与预处理就讲到这里。记住一句话:干净的数据是产业链图谱的命根子。这一步花的时间越多,后面构建图谱、做分析就越省心。