首页 > 解决方案 > DataFrame 在对 groupby 值应用函数后创建新列

问题描述

我有这样一个数据框:

原始数据框

用一个最小的例子:

d = {'Subject': [1,1,1,1,2,2,3,3,3,3,3,3,3], 
    'Pattern': [1,1,2,2,3,3,2,2,2,2,2,2,2], 
    'Time': [0.85, 0.92, 1.03, 1.06, 0.89, 0.85, 1.20, 1.03, 1.25, 100.03, 1.97,0.23,0.64]}
df = pd.DataFrame(data=d)

其中Subject范围从 1 到 8 和Pattern从 1 到 3。我想在分组后创建一个新列,Subject并应用一个函数从与 groupby 关联Pattern的列表中删除异常值。Time现在我有一个运行良好的解决方案,但我想知道是否会有更优雅的解决方案,以便我学习如何更好地与 DataFrame 交互。举个例子,它应该输出:

 Subject Pattern Time Time_2
0   1      1    0.85    0.85
1   1      1    0.92    0.92
2   1      2    1.03    1.03
3   1      2    1.06    1.06
4   2      3    0.89    0.89
5   2      3    0.85    0.85
6   3      2    1.20    1.20
7   3      2    1.03    1.03
8   3      2    1.25    1.25
9   3      2    100.03  0.00 # <---
10  3      2    1.97    1.97
11  3      2    0.23    0.23
12  3      2    0.64    0.64

我当前的代码:

def remove_outliers(arr):
    elements = np.array(arr)

    mean = np.mean(elements)
    sd = np.std(elements)
    
    return [x if (mean - 2 * sd < x <  mean + 2 * sd) else 0 for x in arr]

df_g = df.groupby(['Subject', 'Pattern'])['Time']

times = []
keys = list(df_g.groups.keys())
for i, l in enumerate(df_g.apply(list)):
    times.append((keys[i], remove_outliers(l)))
    
df['Time_2'] = 0
for k, l in times:
    vals = df[(df['Subject'] == k[0]) & (df['Pattern'] == k[1])].index.values
    df['Time_2'].iloc[vals] = l

标签: pythonpandasdataframe

解决方案


试试这个 -

  1. 使用 groupbytransform组获取每行的 GroupWise 平均值和标准差。
  2. check接下来使用这些系列对象根据您的功能创建您的条件。
  3. 接下来将其反转并用于df.mask屏蔽此范围之外的值,并用 0 填充它们。
grouper = df.groupby(['Subject', 'Pattern'])['Time']

mean = grouper.transform('mean')
std = grouper.transform('std').fillna(0)

check = (df['Time'] < (mean - 2*std)) | (df['Time'] > (mean + 2*std))

df['Time_new'] = df['Time'].mask(check).fillna(0)
print(df)
    Subject  Pattern    Time  Time_new
0         1        1    0.85      0.85
1         1        1    0.92      0.92
2         1        2    1.03      1.03
3         1        2    1.06      1.06
4         2        3    0.89      0.89
5         2        3    0.85      0.85
6         3        2    1.20      1.20
7         3        2    1.03      1.03
8         3        2    1.25      1.25
9         3        2  100.03      0.00   #<---
10        3        2    1.97      1.97
11        3        2    0.23      0.23
12        3        2    0.64      0.64

注意:对于您的示例,添加 3 标准偏差条件的 Jsut范围太高。尝试 2标准。


推荐阅读