3. 数据收集与清洗:数据源类型、缺失值处理与异常值检测

数据收集与清洗是特征工程的基础环节,直接影响后续建模质量。本节系统梳理常见数据源类型,并深入讲解缺失值处理与异常值检测的核心方法。

3.1 数据源类型与特征

在MRM(Market Response Model)项目中,数据通常来源于以下三类系统,每类数据在时效性、粒度和可靠性上存在显著差异。

数据源类型 典型来源 粒度 时效性 常见问题
内部交易数据 CRM、ERP、POS 订单/客户级 T+1 字段缺失、重复记录
外部市场数据 第三方调研、行业报告 品牌/品类级 周/月 口径不一致、采样偏差
数字渠道数据 GA、社交媒体、广告平台 用户行为级 实时/T+1 Cookie丢失、归因偏差
实践建议:多源数据合并时,优先以内部交易数据为主表,外部数据做维度补充。合并前务必统一时间戳格式和主键编码规则。

3.2 缺失值处理策略

缺失值处理需根据缺失机制(MCAR/MAR/MNAR)和业务含义选择方法。以下为三种主流填充方式的对比与适用场景。

方法 原理 适用场景 优点 缺点
均值/中位数填充 用该列统计量替换缺失值 数值型、缺失率<5%、MCAR 简单快速、可解释 降低方差、扭曲分布
模型填充 用其他特征预测缺失值(KNN/回归/随机森林) 缺失率5%-30%、特征间相关性强 保留数据分布、精度高 计算成本高、可能过拟合
多重插补 生成多个填充版本,合并估计 学术研究、缺失率>30% 考虑不确定性 实现复杂、解释困难

3.2.1 均值/中位数填充实现

import pandas as pd
import numpy as np

# 示例数据
df = pd.DataFrame({'sales': [100, np.nan, 150, 130, np.nan, 160]})

# 均值填充
df['sales_mean'] = df['sales'].fillna(df['sales'].mean())

# 中位数填充(推荐用于有偏分布)
df['sales_median'] = df['sales'].fillna(df['sales'].median())

print(f"均值: {df['sales'].mean():.2f}, 中位数: {df['sales'].median():.2f}")

3.2.2 模型填充(KNN示例)

from sklearn.impute import KNNImputer

# 假设有多个特征列
data = [[1, 2, np.nan], [3, 4, 3], [np.nan, 6, 5], [7, 8, 9]]
imputer = KNNImputer(n_neighbors=2)

data_imputed = imputer.fit_transform(data)
print(data_imputed)
避坑提示:模型填充时,切勿将目标变量(如销售额)作为预测缺失值的输入特征,否则会造成数据泄露。填充应在训练集上拟合,再转换验证集和测试集。

3.3 异常值检测方法

异常值检测是数据清洗的关键步骤。IQR和Z-score是最常用的两种统计方法,适用于不同分布特征的数据。

异常值检测方法对比流程 原始数据 IQR 方法(四分位距) Z-score 方法(标准分数) 计算 Q1、Q3、IQR = Q3 - Q1 阈值:Q1 - 1.5*IQR / Q3 + 1.5*IQR 计算均值 μ、标准差 σ 阈值:|Z| > 3(或 2.5) 标记异常值 / 替换 / 删除 IQR 适用于偏态分布;Z-score 适用于近似正态分布

3.3.1 IQR方法实现

def detect_outliers_iqr(data, factor=1.5):
    """使用IQR方法检测异常值"""
    Q1 = np.percentile(data, 25)
    Q3 = np.percentile(data, 75)
    IQR = Q3 - Q1

    lower_bound = Q1 - factor * IQR
    upper_bound = Q3 + factor * IQR

    outliers = (data < lower_bound) | (data > upper_bound)
    return outliers, lower_bound, upper_bound

# 示例
sales = [100, 105, 98, 110, 102, 300, 95, 108, 101, 97]
outliers, lb, ub = detect_outliers_iqr(sales)
print(f"异常值索引: {np.where(outliers)[0]}")
print(f"下界: {lb:.2f}, 上界: {ub:.2f}")

3.3.2 Z-score方法实现

from scipy import stats

def detect_outliers_zscore(data, threshold=3):
    """使用Z-score检测异常值"""
    z_scores = np.abs(stats.zscore(data))
    outliers = z_scores > threshold
    return outliers, z_scores

# 示例
sales = [100, 105, 98, 110, 102, 300, 95, 108, 101, 97]
outliers, z = detect_outliers_zscore(sales)
print(f"异常值索引: {np.where(outliers)[0]}")
print(f"最大Z-score: {z.max():.2f}")
方法选择指南:
  • 数据近似正态分布 → 优先使用Z-score(阈值3)
  • 数据偏态明显或含极端值 → 优先使用IQR(系数1.5)
  • 样本量小(<20) → 建议结合业务规则人工判断
  • 高维数据 → 考虑使用孤立森林或LOF算法

3.4 数据清洗流程总结

以下表格汇总了数据收集与清洗阶段的完整工作流,供团队在MRM项目中参考执行。

步骤 操作内容 输出物 质量检查点
1 多源数据接入与格式统一 原始数据宽表 字段类型、主键唯一性
2 缺失值统计与机制分析 缺失率报告 缺失率>50%的字段标记
3 缺失值填充(均值/中位数/模型) 填充后数据集 填充前后分布对比
4 异常值检测(IQR/Z-score) 异常值标记列 异常比例<5%为正常
5 异常值处理(修正/截尾/删除) 清洗后数据集 业务合理性复核
效率技巧:建议将数据清洗逻辑封装为可复用的Pipeline函数,每次迭代只需调整参数(如填充策略、异常阈值),避免重复编码。