跳到主要内容

数据缺失处理

场景描述

用户画像表中 30% 的用户缺少"年龄"字段,用户行为日志偶尔出现 NULL 的 user_id。需要制定缺失数据处理策略。

缺失数据分类

类型英文说明示例
完全随机缺失MCAR缺失与任何变量无关问卷随机跳过某题
随机缺失MAR缺失与其他已知变量有关年龄缺失与注册渠道相关
非随机缺失MNAR缺失与缺失值本身有关高收入用户倾向不填收入
不同类型缺失的处理差异
  • MCAR:可以直接删除,不会引入偏差
  • MAR:可以用其他变量推断填充
  • MNAR:任何填充方法都可能引入偏差,需谨慎处理

处理策略

SQL 层处理

-- 1. 过滤缺失(适用于 MCAR,缺失比例 < 5%)
SELECT * FROM user_profile WHERE age IS NOT NULL;

-- 2. 默认值填充
SELECT user_id,
COALESCE(age, -1) AS age, -- 数值型用 -1 标记
COALESCE(city, '未知') AS city -- 字符串用 '未知'
FROM user_profile;

-- 3. 均值/中位数填充
SELECT user_id,
COALESCE(age, (SELECT PERCENTILE_APPROX(age, 0.5) FROM user_profile WHERE age IS NOT NULL)) AS age
FROM user_profile;

-- 4. 按分组填充(MAR 场景)
SELECT a.user_id,
COALESCE(a.age, b.avg_age) AS age
FROM user_profile a
LEFT JOIN (
SELECT gender, AVG(age) AS avg_age
FROM user_profile WHERE age IS NOT NULL
GROUP BY gender
) b ON a.gender = b.gender;

Python 层处理

import pandas as pd

df = pd.read_sql("SELECT * FROM user_profile", conn)

# 缺失率统计
print(df.isnull().sum() / len(df) * 100)

# 填充策略
df['age'].fillna(df['age'].median(), inplace=True) # 中位数
df['city'].fillna(df.groupby('province')['city'].transform('first'), inplace=True) # 分组填充

缺失率与处理决策

缺失率建议处理
< 5%删除缺失行或简单填充
5%-30%分组均值/中位数填充或模型预测
30%-50%标记为缺失分桶(如"年龄未知"),作为单独特征
> 50%考虑弃用该字段,或补充收集

常见面试问题

Q1: 缺失值直接删除会有什么问题?

答案

  1. 样本偏差:如果缺失不是 MCAR,删除后样本分布会偏移
  2. 信息损失:删除整行会丢失其他完整字段的信息
  3. 样本量减少:特别是多个字段都有缺失时,删除后可能数据量骤降

Q2: A/B 测试中遇到缺失数据怎么办?

答案

  • 不能直接删除:缺失可能与分组有关(如某渠道用户缺失率高),删除会引入选择偏差
  • ITT 分析:按照初始分组分析,缺失值按最保守估计处理
  • 敏感性分析:分别按"缺失都算成功"和"缺失都算失败"两种极端假设分析,看结论是否一致

相关链接