看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gr99123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在真实的数据分析项目中,我们经常会遇到同时包含缺失值和异常值的数据集。如果简单地用全局均值或中位数填充缺失值,可能会掩盖数据中的结构性差异;而忽略异常值又会影响后续建模的准确性。本文将通过一个综合案例,展示如何结合 groupby、fillna 与 clip(或 quantile)等 pandas 常用方法,在分组基础上智能填充缺失值,并对异常值进行识别与处理。通过本案例,你将掌握一种更贴近实际业务场景的数据清洗策略。
假设我们有一份销售记录数据,包含门店(store)、产品类别(category)、销售额(sales)三个字段。部分销售额缺失,且存在明显异常(如负数或远高于正常范围的值)。我们的目标是:
正确结果应满足:
源数据如下(以字符串形式提供):
data = """
store,category,sales
A,Electronics,1200
A,Electronics,
A,Electronics,1300
A,Clothing,400
A,Clothing,
B,Electronics,1500
B,Electronics,9999
B,Clothing,-200
B,Clothing,500
B,Clothing,
"""
读取代码:
import pandas as pd
from io import StringIO
df = pd.read_csv(StringIO(data.strip()))
df['sales'] = pd.to_numeric(df['sales'], errors='coerce')
首先,我们需要按 store 和 category 分组,计算每组 sales 的中位数,用于填充 NaN。这可以通过 groupby().transform('median') 实现,它能返回与原 DataFrame 等长的 Series,便于直接用于 fillna。
接着,为了识别异常值,我们同样基于分组计算每组的 5% 和 95% 分位数(即上下界),然后判断每个值是否落在该区间内。这里可以再次使用 groupby().transform() 配合 quantile 函数获取边界值,再通过布尔运算生成异常标记。
整个过程可以链式完成:先填充缺失值,再基于填充后的列计算分位边界,最后生成 is_outlier 列。
代码如下:
import pandas as pd
from io import StringIO
data = """
store,category,sales
A,Electronics,1200
A,Electronics,
A,Electronics,1300
A,Clothing,400
A,Clothing,
B,Electronics,1500
B,Electronics,9999
B,Clothing,-200
B,Clothing,500
B,Clothing,
"""
df = (
pd.read_csv(StringIO(data.strip()))
.assign(sales=lambda x: pd.to_numeric(x['sales'], errors='coerce'))
.assign(
sales_filled=lambda x: x['sales'].fillna(
x.groupby(['store', 'category'])['sales'].transform('median')
)
)
.assign(
lower_bound=lambda x: x.groupby(['store', 'category'])['sales_filled'].transform(lambda s: s.quantile(0.05)),
upper_bound=lambda x: x.groupby(['store', 'category'])['sales_filled'].transform(lambda s: s.quantile(0.95))
)
.assign(
is_outlier=lambda x: (x['sales_filled'] < x['lower_bound']) | (x['sales_filled'] > x['upper_bound'])
)
.drop(columns=['lower_bound', 'upper_bound'])
)
print(df)
'''
store category sales sales_filled is_outlier
0 A Electronics 1200.0 1200.0 True
1 A Electronics NaN 1250.0 False
2 A Electronics 1300.0 1300.0 True
3 A Clothing 400.0 400.0 False
4 A Clothing NaN 400.0 False
5 B Electronics 1500.0 1500.0 True
6 B Electronics 9999.0 9999.0 True
7 B Clothing -200.0 -200.0 True
8 B Clothing 500.0 500.0 True
9 B Clothing NaN 150.0 False
'''
代码分析:
assign 实现链式操作,每一步都清晰定义新列;groupby().transform('median') 用于智能填充缺失值,保留组内结构;transform(lambda s: s.quantile(...)) 动态计算每组的分位边界;is_outlier 标记,并清理中间列;最终输出将显示原始 sales、填充后的 sales_filled 以及是否为异常值,便于后续决策(如剔除、修正或单独分析异常样本)。
(完)
更新时间:2025-11-22 11:40:29 标签:pandas python 缺失值 异常模式