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)
我的小技巧:阈值别设太高也别设太低。85分左右是个不错的起点。我曾经设了95,结果「华为技术」和「华为技术有限公司」被当成两个实体,后来调低到80又误杀了太多。多试几次,找到那个平衡点。

4.2 缺失值处理:别让「空」变成「坑」

产业链数据里,缺失值太常见了。尤其是上下游关系、产能数据这些字段,经常是空的。怎么处理?我一般分三步走。

4.2.1 先诊断,再下药

别一上来就填值。先看看缺失率有多高,缺失模式是什么样的。

# 快速查看缺失情况
import missingno as msno
msno.matrix(df)

这张图能告诉你:哪些列缺失严重,哪些行是「重灾区」。如果一列缺失超过70%,我建议直接扔掉——硬填进去也是噪声。

4.2.2 分类处理策略

字段类型 缺失率 推荐处理方式
企业名称 <5% 删除该行
注册资本 10%-30% 用行业均值填充
上下游关系 30%-50% 用知识图谱推理补全
产能数据 >50% 标记为「未知」,单独处理
注意:千万不要对所有缺失值用同一种方法。我曾经见过有人把所有空值都填0,结果产能为0的企业被当成「停产」,整个产业链分析全偏了。

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多分,但通过知识库一查,发现是同一家,这才对齐成功。

实体对齐的黄金法则:
  1. 先精确,再模糊,最后推理
  2. 保留对齐置信度,低置信度的标记为「待人工审核」
  3. 建立实体映射表,方便后续增量更新

4.5 本章知识体系总览

下面这张图,是我自己梳理的数据清洗与预处理全流程。你看一遍,基本就知道每一步该做什么了。

数据清洗与预处理全流程 原始产业链数据 数据去重 完全重复删除 关键字段去重 语义模糊去重 缺失值处理 缺失率诊断 分类填充策略 标记未知值 文本标准化 大小写统一 全半角转换 格式规范化 实体对齐 精确匹配 模糊匹配 知识库推理 清洗后的标准化数据 产业链图谱构建

嗯,这张图基本把咱们这一章的核心逻辑串起来了。你仔细看,四个模块是并行的,但顺序上我建议先做去重和缺失值处理,再做标准化,最后做实体对齐。为什么?因为去重和缺失值处理能减少数据量,后面的步骤就轻松多了。

好了,数据清洗与预处理就讲到这里。记住一句话:干净的数据是产业链图谱的命根子。这一步花的时间越多,后面构建图谱、做分析就越省心。