4. 缺失值检测与处理:识别样本中的缺失值模式
知识图谱构建过程中,样本缺失值是最常见的数据质量问题之一。缺失值不仅会降低模型训练的有效性,还会在实体对齐、关系抽取等下游任务中引入系统性偏差。本章聚焦于如何系统性地检测样本中的缺失值模式,并通过可视化手段辅助决策,最终选择合理的填充或删除策略。
4.1 缺失值模式分类
在知识图谱样本中,缺失值并非随机出现,通常呈现三种结构模式。理解这些模式是选择处理策略的前提。
| 缺失模式 | 定义 | 知识图谱场景示例 | 处理倾向 |
|---|---|---|---|
| 完全随机缺失 (MCAR) | 缺失与任何观测数据无关 | 传感器随机故障导致的关系属性缺失 | 可直接删除或简单填充 |
| 随机缺失 (MAR) | 缺失依赖于其他观测变量 | 长尾实体更易缺失“别名”属性 | 需借助其他特征建模填充 |
| 非随机缺失 (MNAR) | 缺失依赖于缺失值本身 | 高收入实体故意隐藏“收入”属性 | 需领域知识或敏感处理 |
校验提示: 在知识图谱样本中,MNAR 模式最容易引入样本偏差。例如,如果缺失“出生日期”的实体集中在某个地域,后续基于年龄的统计分析将产生系统性偏移。务必在检测阶段标记此类模式。
4.2 使用 isnull() 进行缺失值检测
Pandas 的 isnull() 方法是缺失值检测的起点。它返回一个布尔型 DataFrame,标识每个单元格是否为缺失值。结合 sum() 和 mean() 可以快速获取缺失概览。
import pandas as pd
import numpy as np
# 模拟知识图谱样本数据
kg_sample = pd.DataFrame({
'entity_id': ['E001', 'E002', 'E003', 'E004', 'E005'],
'type': ['Person', 'Organization', 'Person', 'Person', 'Organization'],
'name': ['Alice', 'Acme Corp', np.nan, 'Bob', 'Beta Inc'],
'birth_year': [1990, np.nan, 1985, np.nan, np.nan],
'revenue': [np.nan, 5000000, np.nan, np.nan, 3000000],
'country': ['US', 'US', 'CN', np.nan, 'CN']
})
# 缺失值数量统计
print(kg_sample.isnull().sum())
# 缺失值比例统计
print(kg_sample.isnull().mean().round(3) * 100)
输出示例:
entity_id 0
type 0
name 1
birth_year 3
revenue 3
country 1
dtype: int64
entity_id 0.0
type 0.0
name 20.0
birth_year 60.0
revenue 60.0
country 20.0
dtype: float64
关键指标: 当某列缺失比例超过 50% 时,需谨慎评估该属性在知识图谱中的保留价值。上例中
birth_year 和 revenue 缺失率达 60%,应考虑是否从图谱模式中移除或使用外部知识库补全。
4.3 使用热力图可视化缺失模式
单纯的数据表格难以直观呈现缺失值的分布规律。使用 Seaborn 的 heatmap 结合 isnull() 可以生成缺失值热力图,快速识别缺失的聚集区域和行间模式。
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(10, 6))
sns.heatmap(kg_sample.isnull(), cbar=False, cmap='viridis', yticklabels=False)
plt.title('知识图谱样本缺失值热力图', fontsize=14)
plt.xlabel('属性列')
plt.ylabel('样本行')
plt.tight_layout()
plt.show()
热力图中黄色表示存在值,紫色表示缺失值。通过观察紫色块的分布,可以判断缺失是随机散布还是集中在特定行或列。
4.4 缺失值处理策略:填充与删除
根据检测结果和缺失模式,选择以下策略之一进行处理。每种策略都有其适用场景和潜在风险。
4.4.1 删除策略
- 行删除(listwise deletion): 直接删除包含缺失值的整行样本。适用于 MCAR 模式且缺失比例较低(<5%)的场景。
- 列删除: 当某属性缺失比例过高(>50%)且无法通过外部知识补全时,从图谱模式中移除该属性。
- 成对删除(pairwise deletion): 仅在计算特定属性对时排除缺失值,保留其他可用数据。适用于相关性分析阶段。
偏差风险警告: 在知识图谱中,如果缺失值集中在某个特定实体类型或关系方向上,直接行删除会导致该类型样本系统性减少,破坏图谱的覆盖均衡性。务必在删除前按实体类型分层统计缺失率。
4.4.2 填充策略
| 填充方法 | 适用数据类型 | 知识图谱场景示例 | 注意事项 |
|---|---|---|---|
| 固定值填充 | 类别型 / 数值型 | 缺失“国家”填充为“Unknown” | 可能引入“未知”类别的聚集偏差 |
| 均值/中位数填充 | 数值型 | 缺失“收入”填充为同类实体中位数 | 降低方差,削弱极端值影响 |
| 众数填充 | 类别型 | 缺失“类型”填充为最频繁出现的类型 | 强化头部类别,削弱尾部类别 |
| 前向/后向填充 | 时序型 | 缺失“时间戳”使用相邻实体记录填充 | 仅适用于有序数据 |
| 模型预测填充 | 任意型 | 使用 KNN 或回归模型基于其他属性预测缺失值 | 计算成本高,可能过拟合 |
# 填充策略代码示例
from sklearn.impute import SimpleImputer
# 数值列:使用中位数填充
num_imputer = SimpleImputer(strategy='median')
kg_sample[['birth_year', 'revenue']] = num_imputer.fit_transform(kg_sample[['birth_year', 'revenue']])
# 类别列:使用众数填充
cat_imputer = SimpleImputer(strategy='most_frequent')
kg_sample[['name', 'country']] = cat_imputer.fit_transform(kg_sample[['name', 'country']])
print("填充后数据:")
print(kg_sample)
4.5 填充后的偏差校验
填充操作本身可能引入新的偏差。完成填充后,必须进行以下校验:
- 分布对比: 比较填充前后各属性的均值、方差、分位数分布,确保填充未显著改变原始分布形态。
- 类别比例校验: 对于类别型属性,检查填充后各类别占比是否与原始非缺失数据一致。
- 实体类型分层校验: 按实体类型(Person / Organization)分层统计填充量,避免某一类型被过度填充。
# 填充前后分布对比校验
print("填充前 birth_year 统计:")
print(kg_sample['birth_year'].describe())
print("\n填充后 birth_year 统计:")
print(kg_sample['birth_year'].describe())
# 类别比例校验
print("\n填充后 country 分布:")
print(kg_sample['country'].value_counts(normalize=True))
最佳实践: 在知识图谱项目中,建议保留原始缺失标记列(如
birth_year_missing 布尔列),以便在后续分析中追溯填充操作的影响。同时,将填充策略作为元数据记录在图谱的 provenance 层中。