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是最常用的两种统计方法,适用于不同分布特征的数据。
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函数,每次迭代只需调整参数(如填充策略、异常阈值),避免重复编码。