3、数据清洗基础:缺失值处理、异常值检测与重复数据处理
数据清洗,说白了就是给数据「洗澡」。我见过太多人拿到数据直接开跑模型,结果一塌糊涂。为什么?因为脏数据会骗人。今天咱们就把清洗这件事聊透。
3.1 缺失值处理:别让「空」坑了你
缺失值是最常见的问题。我个人习惯,拿到数据第一件事就是 df.isnull().sum()。先看看哪些列有缺失,缺了多少。
3.1.1 删除法:简单粗暴
如果缺失比例很小,比如不到5%,直接删掉最省事。我在项目中遇到过,某个特征缺失了80%,留着反而干扰模型。
# 删除缺失值所在的行
df.dropna(inplace=True)
# 删除缺失比例超过50%的列
df.dropna(thresh=len(df) * 0.5, axis=1, inplace=True)
⚠️ 注意: 删除前一定要确认数据分布没变。我曾经删完才发现样本不平衡了,模型直接偏了。
3.1.2 填充法:用「合理值」填空
填充比删除更常用。你想想看,如果缺失的是年龄,用均值填充就挺合理。
# 均值填充
df['age'].fillna(df['age'].mean(), inplace=True)
# 中位数填充(适合有异常值的情况)
df['income'].fillna(df['income'].median(), inplace=True)
# 众数填充(适合类别特征)
df['gender'].fillna(df['gender'].mode()[0], inplace=True)
💡 小技巧: 我习惯先画个分布图,看看填充前后分布是否一致。如果变了,说明填充方式有问题。
3.1.3 插值法:让数据「顺滑」起来
插值适合时间序列数据。比如传感器每隔1秒采集一次,中间断了,用前后值插一下很自然。
# 线性插值
df['temperature'].interpolate(method='linear', inplace=True)
# 时间插值(适合时间序列)
df['value'].interpolate(method='time', inplace=True)
嗯,这里要注意:插值假设数据是平滑变化的。如果数据波动很大,插值反而会引入偏差。
3.2 异常值检测:揪出「捣乱分子」
异常值就是那些明显偏离正常范围的值。比如年龄200岁,月薪100万。这些值会严重拉偏模型。
3.2.1 3σ原则:简单有效
如果数据服从正态分布,超过均值±3个标准差的值就是异常。我刚开始做数据时就用这招,简单粗暴。
mean = df['value'].mean()
std = df['value'].std()
df = df[(df['value'] >= mean - 3*std) & (df['value'] <= mean + 3*std)]
3.2.2 IQR方法:更稳健
如果数据不是正态分布,用IQR更靠谱。它基于四分位数,不受极端值影响。
Q1 = df['value'].quantile(0.25)
Q3 = df['value'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
df = df[(df['value'] >= lower) & (df['value'] <= upper)]
🔑 核心要点: 异常值不一定要删除。我遇到过一些异常值其实是「信号」,比如信用卡欺诈检测,异常交易才是关键。
3.2.3 异常值处理策略
| 策略 | 适用场景 | 注意事项 |
|---|---|---|
| 删除 | 异常值极少,且确认是错误 | 不要删除超过5%的数据 |
| 截尾 | 异常值较多,但不想丢失样本 | 用上下限替换,保留样本量 |
| 单独处理 | 异常值本身有价值 | 单独建模或标记为特殊类别 |
3.3 重复数据处理:别让「复制粘贴」骗了你
重复数据会让模型「过度学习」某些样本。我见过一个项目,因为数据采集时重复记录了,导致模型在测试集上表现虚高。
3.3.1 完全重复:直接删除
# 删除完全重复的行
df.drop_duplicates(inplace=True)
# 基于特定列去重
df.drop_duplicates(subset=['user_id', 'timestamp'], keep='first', inplace=True)
3.3.2 部分重复:需要判断
有时候两行数据大部分相同,只有个别字段不同。比如用户信息更新了,但旧记录没删。这时候需要根据业务逻辑判断保留哪条。
# 按用户ID分组,保留最新记录
df.sort_values('update_time', inplace=True)
df.drop_duplicates(subset='user_id', keep='last', inplace=True)
⚠️ 避坑指南: 我曾经以为重复数据删掉就完事了,结果发现有些「重复」其实是业务上的正常记录。比如用户多次购买同一种商品,这不是重复,是真实行为。一定要先理解业务再动手。
3.4 实战建议:清洗流程
我个人习惯按这个顺序来:
- 先看整体:用
df.info()和df.describe()了解数据概况 - 处理缺失值:先填充,再考虑删除
- 检测异常值:用可视化 + 统计方法结合
- 去重:最后做,因为前面操作可能产生新的重复
- 验证结果:清洗前后对比分布,确保没引入新问题
你想想看,数据清洗花的时间往往比建模还多。但这一步做扎实了,后面模型的效果才有保障。嗯,今天就聊到这,下次咱们讲特征编码。