在数据分析和机器学习的工作流中,数据清洗是绕不开的关键环节。粗糙的数据就像未打磨的原石,即便算法再精妙,也难以提炼出有价值的信息。其中,缺失数据与异常值是最常见的两类问题,它们不仅会干扰统计分析结果,还可能导致模型训练出现偏差。本文将结合Python实战,系统讲解这两类问题的处理方法。

一、缺失数据:看不见的“数据黑洞”

缺失数据指的是数据集中存在的空白或无效值,通常以NaN(Not a Number)或None的形式出现。它们可能源于数据采集时的遗漏、存储错误或者用户未填写等原因。

1. 缺失数据的识别

在Python中,我们可以借助pandas库快速定位缺失值:


Python

复制

import pandas as pd import numpy as np # 创建含缺失值的示例数据集 data = pd.DataFrame({ 'A': [1, 2, np.nan, 4], 'B': [5, np.nan, np.nan, 8], 'C': [9, 10, 11, 12] }) # 查看每个特征的缺失值数量 print(data.isnull().sum()) # 查看数据集整体缺失情况 print(data.isnull().mean() * 100) # 以百分比显示

2. 缺失数据的处理策略

处理缺失值没有绝对最优的方法,需结合业务场景和数据分布选择合适的方案:

  • 删除法:适用于缺失比例极低(如<5%)或缺失值随机分布的情况

    
    

    Python

    复制

    # 删除含缺失值的行 data_drop_row = data.dropna(axis=0) # 删除含缺失值的列 data_drop_col = data.dropna(axis=1)

  • 填充法:最常用的处理方式,分为简单填充和智能填充

    
    

    Python

    复制

    # 均值填充(适用于正态分布的数值型数据) data_fill_mean = data.fillna(data.mean()) # 中位数填充(适用于存在异常值的数值型数据) data_fill_median = data.fillna(data.median()) # 众数填充(适用于分类数据) data_fill_mode = data.fillna(data.mode().iloc[0]) # 前向填充/后向填充(适用于时间序列数据) data_fill_ffill = data.fillna(method='ffill') # 前向填充 data_fill_bfill = data.fillna(method='bfill') # 后向填充

  • 模型预测法:对于缺失比例较高的特征,可以用其他特征构建模型预测缺失值

    
    

    Python

    复制

    from sklearn.ensemble import RandomForestRegressor # 分离含缺失值的特征和其他特征 data_train = data[data['A'].notnull()] data_test = data[data['A'].isnull()] # 训练模型 model = RandomForestRegressor() model.fit(data_train[['B', 'C']], data_train['A']) # 预测缺失值 data.loc[data['A'].isnull(), 'A'] = model.predict(data_test[['B', 'C']])

二、异常值:数据中的“离群者”

异常值是指与其他数据点显著偏离的值,可能是真实的极端情况,也可能是数据录入错误。异常值会严重影响统计分析的结果,比如拉高均值、扩大方差。

1. 异常值的识别

常用的异常值检测方法包括:

  • 统计分析法:基于正态分布的3σ原则,超出均值±3倍标准差的值视为异常值

    
    

    Python

    复制

    # 计算均值和标准差 mean = data['A'].mean() std = data['A'].std() # 识别异常值 outliers = data[(data['A'] < mean - 3*std) | (data['A'] > mean + 3*std)]

  • 四分位数法(IQR):不受分布假设影响,更适合非正态分布数据

    
    

    Python

    复制

    # 计算四分位数和四分位距 q1 = data['A'].quantile(0.25) q3 = data['A'].quantile(0.75) iqr = q3 - q1 # 识别异常值 outliers = data[(data['A'] < q1 - 1.5*iqr) | (data['A'] > q3 + 1.5*iqr)]

  • 可视化法:通过箱线图、散点图直观识别异常值

    
    

    Python

    复制

    import matplotlib.pyplot as plt # 绘制箱线图 plt.boxplot(data['A']) plt.title('Boxplot of Feature A') plt.show()

2. 异常值的处理策略

处理异常值需先判断其产生原因,再选择对应策略:

  • 删除法:适用于异常值为数据录入错误的情况

    
    

    Python

    复制

    # 删除异常值所在行 data_clean = data[(data['A'] >= q1 - 1.5*iqr) & (data['A'] <= q3 + 1.5*iqr)]

  • 修正法:若异常值为真实数据但超出合理范围,可以进行截断处理

    
    

    Python

    复制

    # 截断异常值到合理范围 data['A'] = np.where(data['A'] > q3 + 1.5*iqr, q3 + 1.5*iqr, data['A']) data['A'] = np.where(data['A'] < q1 - 1.5*iqr, q1 - 1.5*iqr, data['A'])

  • 分箱法:将数值型数据划分为不同区间,弱化异常值的影响

    
    

    Python

    复制

    # 等频分箱 data['A_bin'] = pd.qcut(data['A'], q=4, labels=['Q1', 'Q2', 'Q3', 'Q4'])

  • 保留法:若异常值代表真实的极端情况(如用户消费峰值),可以保留并在建模时使用对异常值不敏感的算法(如决策树、随机森林)

三、数据清洗的最佳实践
  1. 先分析后处理:在处理缺失值和异常值前,务必先分析其产生原因和分布特征,避免盲目操作
  2. 记录清洗过程:详细记录每一步清洗操作,保证数据处理的可追溯性
  3. 验证清洗效果:清洗完成后,通过统计指标和可视化方法验证数据质量是否提升
  4. 结合业务场景:所有处理方法都应服务于业务目标,避免为了清洗而清洗

金句:数据清洗的本质不是消除所有“不完美”,而是让数据更贴合业务需求,为后续分析和建模提供可靠基础。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐