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

使用groupby+apply结合np.select函数时输出异常,期望得到可合并回原DataFrame的单列标记结果

groupby+apply结合np.select函数时输出异常,期望得到可合并回原DataFrame的单列标记结果

嘿,我来帮你解决这个问题~

你现在遇到的核心问题是:用groupby.apply之后得到的是按星期几分组的结果集合,每个分组对应一个异常值标记的列表,没法直接和原DataFrame的行一一对应。这是因为apply默认会把每个分组的处理结果打包成单个元素,最终返回的是以分组键为索引的Series,而不是和原数据对齐的逐行结果。

解决方案

我们只需要调整处理逻辑,让分组后的结果能自动匹配原DataFrame的索引,这里有两种简单好用的方法:

方法1:修改函数返回带原索引的Series

你的is_outlier函数里,参数x其实是每个分组对应的、带有原DataFrame索引的Series,所以不用把结果转成列表,直接返回标记后的Series即可:

import pandas as pd
import numpy as np

# 修正原数据的笔误:randint不是randin,2024年是闰年,日期范围共366天
df = pd.DataFrame({'datecol' : pd.date_range('2024-1-1', '2024-12-31'),
                   'val' : np.random.randint(low = 100, high = 5000, size = 366)})

def is_outlier(x):
    iqr = x.quantile(.75) - x.quantile(.25)
    lower_bound = x.quantile(.25) - 1.5*iqr
    upper_bound = x.quantile(.75) + 1.5*iqr
    # 判断异常值,直接返回带原索引的Series,转成int类型(1=异常,0=正常)
    outlier_mask = (x <= lower_bound) | (x >= upper_bound)
    return outlier_mask.astype(int)

# apply后自动拼接成和原df对齐的Series,直接添加为新列
df['outlier_flag'] = df.groupby(df['datecol'].dt.weekday)['val'].apply(is_outlier)

方法2:使用transform代替apply(更推荐)

transform是Pandas专门为这种场景设计的工具:它会自动把分组处理后的结果映射回原数据的对应行,代码更简洁直观:

import pandas as pd
import numpy as np

df = pd.DataFrame({'datecol' : pd.date_range('2024-1-1', '2024-12-31'),
                   'val' : np.random.randint(low = 100, high = 5000, size = 366)})

def is_outlier(x):
    iqr = x.quantile(.75) - x.quantile(.25)
    lower = x.quantile(.25) - 1.5*iqr
    upper = x.quantile(.75) + 1.5*iqr
    return ((x <= lower) | (x >= upper)).astype(int)

# 用transform直接得到和原df行数完全一致的结果列
df['outlier_flag'] = df.groupby(df['datecol'].dt.weekday)['val'].transform(is_outlier)

这样处理后,outlier_flag列就会和原DataFrame的每一行一一对应,你可以直接用它做后续的数据分析啦~

备注:内容来源于stack exchange,提问作者Karthik S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:04:31