Python案例如何剔除异常数据?

wen python案例 53

本文目录导读:

Python案例如何剔除异常数据?

  1. 目录导读
  2. 异常数据是什么?为何必须处理?
  3. 如何快速识别异常数据?
  4. Python剔除异常的6种核心方法
  5. 实战案例:电商用户交易数据清洗
  6. 常见问题与避坑指南(Q&A 问答)

Python实战指南:如何精准剔除异常数据?6种核心方法深度解析

目录导读

  1. 异常数据是什么?为何必须处理?(常见来源与危害)
  2. 如何快速识别异常值?(可视化+统计指标)
  3. Python剔除异常的6种核心方法(Z-score、IQR、DBSCAN等)
  4. 实战案例:电商用户交易数据清洗(代码+结果演示)
  5. 常见问题与避坑指南(Q&A 问答环节)

异常数据是什么?为何必须处理?

异常数据(Outlier)是指显著偏离正常范围的数据点,用户年龄填写为200岁、销售额突然飙升到正常值的100倍、传感器记录到负温度等。

异常数据的常见来源:

  • 手动输入错误(如多打一个0)
  • 设备故障(传感器间歇性失灵)
  • 数据采集异常(网络波动导致数值浮空)
  • 业务中的特殊事件(促销导致的短期峰值,需判断是否剔除)

若不处理:

  • 均值、标准差等统计量失真 → 模型偏差
  • 回归模型拟合被“带偏” → 预测效果差
  • 聚类结果产生分离的噪声簇 → 业务误判

如何快速识别异常数据?

我们不能盲目剔除任何看起来“离谱”的数值,必须先识别,推荐两步走:

基础探索性分析

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.read_csv('transaction.csv')
df.describe()           # 看数值列的min、max、25%、75%分位
df['amount'].hist()     # 直方图:看数据分布形状,是否有尾部拖长

当最大值远超75%分位 + 3倍IQR时,很可能存在异常。

箱线图(Boxplot)一瞥

plt.boxplot(df['amount'])'交易金额箱线图')
plt.show()

箱线图中,超出上下须(Q1-1.5IQR、Q3+1.5IQR)的点会被标记为异常。

🔍 小工具:也可以用df['amount'].plot(kind='box')快速出图。


Python剔除异常的6种核心方法

以下排序从简单到复杂,你可以根据数据分布特征选择最合适的。

方法1:Z-score法(正态分布假设)

from scipy import stats
z = np.abs(stats.zscore(df['amount']))
threshold = 3   # 常用3倍标准差
df_clean = df[(z < threshold)]

适用:数据大致呈正态分布时效果好,如果数据有偏态,Z-score会误判。

方法2:IQR四分位距法(稳健,不依赖分布)

Q1 = df['amount'].quantile(0.25)
Q3 = df['amount'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df_clean = df[(df['amount'] >= lower_bound) & (df['amount'] <= upper_bound)]

适用:偏斜分布、有厚尾的数据,也是数据分析师最常用的方法之一。

方法3:MAD(绝对中位差)法(抗10%异常)

median = df['amount'].median()
mad = np.median(np.abs(df['amount'] - median))
threshold = 3 * mad   # 常用3倍MAD
df_clean = df[np.abs(df['amount'] - median) < threshold]

适用:数据有较多异常,或Z-score失效时,MAD比标准差更鲁棒。

方法4:DBSCAN密度聚类(多维异常检测)

from sklearn.cluster import DBSCAN
clustering = DBSCAN(eps=0.5, min_samples=5).fit(df[['amount', 'user_id']])
df_clean = df[clustering.labels_ != -1]  # -1标记为噪声/异常

适用:多维度同时看异常(如金额+时间+用户等级),但需要调整eps与min_samples参数。

方法5:Isolation Forest(孤立森林,面向高维)

from sklearn.ensemble import IsolationForest
iso = IsolationForest(contamination=0.05, random_state=42)
df['outlier'] = iso.fit_predict(df[['amount', 'order_count', 'user_age']])
df_clean = df[df['outlier'] == 1]  # 1表示正常,-1表示异常

适用:高维数据集(特征数>10),不需要假设数据分布。

方法6:业务规则判断(最终兜底)

手动设定阈值:比如df[df['amount'] < 10000](剔除单笔超万元的交易),这是很多真实清洗场景最后一道防线。


实战案例:电商用户交易数据清洗

背景:某电商表记录了10000条用户订单,字段包括user_id, amount, order_time, city,已知amount列有异常值(如219837元、-50元、0元)。

步骤1:数据探索

print(df['amount'].describe())
# 输出:min=-50, max=219837, 50%=268, mean=512

明显看到最大值219837远超正常范围,且有负值。

步骤2:先用IQR法剔除极端异常

Q1 = df['amount'].quantile(0.25)
Q3 = df['amount'].quantile(0.75)
IQR = Q3 - Q1
df = df[(df['amount'] >= Q1 - 1.5*IQR) & (df['amount'] <= Q3 + 1.5*IQR)]
# 此时还剩下从0到2000左右的正常范围

步骤3:二次过滤业务规则

# 剔除金额≤0的记录(可能是测试或退款数据)
df = df[df['amount'] > 0]
# 剔除大于5000(根据业务经验,该平台最高客单价是4999)
df = df[df['amount'] <= 5000]

步骤4:验证清洗结果

print('剩余记录数:', len(df))
print('金额范围:', df['amount'].min(), '-', df['amount'].max())
# 输出:剩余记录数9861,金额范围10 - 4999

数据从10,000条清洗到9,861条,去除了139条异常记录,后续用于建模的amount列分布变得集中、合理。


常见问题与避坑指南(Q&A 问答)

Q1:Z-score法为什么有时会误删大量正常数据?
A:当数据本身有偏斜(例如电商订单金额右偏严重),用3倍标准差会囊括大量尾部数据,因为标准差被异常拉大,导致正常的高额订单反被误判,此时应优先选择IQR或MAD法。

Q2:删除异常值后,数据量减少了,可以补齐吗?
A:一般不推荐补齐异常值,因为异常数据本身就是噪声,补齐会引入错误,除非你能明确知道该异常值应是某个阈值(比如超出5000就截断为5000),建议:剔除后记录清楚剔除规则,并在报告里说明。

Q3:Isolation Forest与DBSCAN有何区别?
A:Isolation Forest基于“异常容易被孤立”的思想,适合高维、数据量大场景;DBSCAN基于密度聚类,要求特征数(维度)不宜过高(<10),且需要手动调整eps半径,对密度不均的数据较敏感。

Q4:如何判断一个值是异常,还是业务中的正常波动?
A:必须结合业务知识,例如双11当天的订单金额比平时高10倍,这不适合去掉,建议在清洗前先标记时间段,分群处理,另一个方法:用rolling mean(滑动均值)检测,比如超出均值5倍标准差且连续3天不回弹时再剔除。

Q5:使用上面的方法需要安装哪些Python库?
A:核心库:pandas, numpy, scipy, matplotlib,进阶:scikit-learn(Isolation Forest、DBSCAN),可以直接用pip install pandas numpy scipy matplotlib scikit-learn一次搞定。

Q6:异常剔除后,数据量是否一定变少?
A:不一定,如果你的数据里没有异常,有的方法(比如IQR)也可能不删任何行,或者你选用“截断”(Winsorization)而非剔除,将异常值替换为边界值,则行数不变,视业务需要而定。


剔除异常数据不是一次性的“一删了之”,而是结合统计方法与业务理解的平衡术,从最简单的Z-score到更鲁棒的IQR、MAD,再到多维检测的Isolation Forest,Python给了我们一整套工具箱,建议从一个简单的箱线图可视化开始,逐步加入后处理规则,在每步操作后都describe()一把,确保清洗既干净又不伤害核心业务规律。

抱歉,评论功能暂时关闭!