You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas按双列分组查找异常值并用组中位数替换

问题背景

在基于分组与日期维度查找DataFrame异常值时存在实现障碍,需求为:定位并替换指定异常值——2022-06-27日期下A组的数值10、B组的数值20,分别替换为对应分组同日期的中位数(前者替换为3,后者替换为4)。
原问题提供的样例代码与数据(存在列名笔误):

index = [0,1,2,3,4,5,6,7,8,9,10,11]
s = pd.Series(['A','A','A','A','A','A','B','B','B','B','B','B'],index= index)
t = pd.Series(['2022-06-28','2022-06-28','2022-06-28','2022-06-27','2022-06-27','2022-06-27',
               '2022-06-28','2022-06-28','2022-06-28','2022-06-27','2022-06-27','2022-06-27'],index= index)
r = pd.Series([1,2,1,2,3,10,2,3,2,3,4,20],index= index)
df = pd.DataFrame(s,columns = ['group'])
df['date'] = t
df['vale'] = r

print (df)

目标数据结构:

group        date  val
0      A  2022-06-28    1
1      A  2022-06-28    2
2      A  2022-06-28    1
3      A  2022-06-27    2
4      A  2022-06-27    3
5      A  2022-06-27   10
6      B  2022-06-28    2
7      B  2022-06-28    3
8      B  2022-06-28    2
9      B  2022-06-27    3
10     B  2022-06-27    4
11     B  2022-06-27   20
实现步骤
  • 修正列名笔误:原代码赋值数值列时用的列名是vale,和打印输出的val不一致,先统一列名避免运行报错
  • 计算分组中位数:以group、date为联合维度分组,计算每个分组下数值列的中位数,作为异常值的替换基准
  • 定位异常行:如果已知明确的异常值特征,可以直接通过布尔筛选定位行;如果需要通用检测能力,可以用IQR、3σ等离群点检测规则自动识别异常值
  • 批量替换值:将定位到的异常位置的数值,替换为所属分组的中位数即可
完整可运行代码
import pandas as pd

# 构造样例数据(已修正列名笔误)
index = [0,1,2,3,4,5,6,7,8,9,10,11]
s = pd.Series(['A','A','A','A','A','A','B','B','B','B','B','B'],index= index)
t = pd.Series(['2022-06-28','2022-06-28','2022-06-28','2022-06-27','2022-06-27','2022-06-27',
               '2022-06-28','2022-06-28','2022-06-28','2022-06-27','2022-06-27','2022-06-27'],index= index)
r = pd.Series([1,2,1,2,3,10,2,3,2,3,4,20],index= index)
df = pd.DataFrame(s,columns = ['group'])
df['date'] = t
df['val'] = r

# 计算每个(分组+日期)对应的中位数
group_median_map = df.groupby(['group', 'date'])['val'].median().to_dict()

# 方法1:已知异常值精准替换(适配本次明确知道两个异常点的场景)
df.loc[
    (df['date'] == '2022-06-27') & (df['group'] == 'A') & (df['val'] == 10),
    'val'
] = group_median_map[('A', '2022-06-27')]

df.loc[
    (df['date'] == '2022-06-27') & (df['group'] == 'B') & (df['val'] == 20),
    'val'
] = group_median_map[('B', '2022-06-27')]

# 方法2:通用异常自动识别替换(基于IQR规则,无需手动指定异常值,取消注释即可直接使用)
# for (group_name, date_val), sub_df in df.groupby(['group', 'date']):
#     q1 = sub_df['val'].quantile(0.25)
#     q3 = sub_df['val'].quantile(0.75)
#     iqr = q3 - q1
#     upper_bound = q3 + 1.5 * iqr
#     lower_bound = q1 - 1.5 * iqr
#     # 替换超出上下界的离群值为分组中位数
#     df.loc[
#         (df['group'] == group_name) & (df['date'] == date_val) & 
#         ((df['val'] > upper_bound) | (df['val'] < lower_bound)),
#         'val'
#     ] = sub_df['val'].median()

print(df)

运行后索引5的原值10将替换为3,索引11的原值20将替换为4,符合需求。

内容的提问来源于stack exchange,提问作者Itisai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 14:09:22