首页 > 解决方案 > 是否可以在 pandas groupby 转换中访问列名?

问题描述

我的理想问题是“如何访问 pandas DataFrameGroupBy.transform 中的列?”,但在执行了一些测试(此处显示)之后,我想知道这是否可能。

我想访问列名,就像我可以使用的一样apply,但使用transform

例如,给定这个样本数据:

import numpy as np
import pandas as pd

np.random.seed(123)
numeric_data = np.random.rand(9, 3)
cat_data = [f'grp_{i}' for i in range(1,4)] * 3
df = pd.DataFrame(numeric_data, columns=list('ABC')).assign(D = cat_data)
print(df)
          A         B         C      D
0  0.696469  0.286139  0.226851  grp_1
1  0.551315  0.719469  0.423106  grp_2
2  0.980764  0.684830  0.480932  grp_3
3  0.392118  0.343178  0.729050  grp_1
4  0.438572  0.059678  0.398044  grp_2
5  0.737995  0.182492  0.175452  grp_3
6  0.531551  0.531828  0.634401  grp_1
7  0.849432  0.724455  0.611024  grp_2
8  0.722443  0.322959  0.361789  grp_3

我如何使用transform从 A 中减去 B,然后乘以 C?可能吗?
我知道通过apply可以轻松地通过使用lambda或传递用户定义的函数来实现,如下所示:

def customFunc(grp):
    return (grp['A'] - grp['B']) * grp['C']

df.groupby('D').apply(customFunc)
D       
grp_1  0    0.093084
       3    0.035679
       6   -0.000175
grp_2  1   -0.071147
       4    0.150817
       7    0.076364
grp_3  2    0.142324
       5    0.097464
       8    0.144529
dtype: float64

但是,输出值是未排序的(如您在内部索引中所见),因此我不能将这个输出原样放在新列中。一个选项是预先使用 apply 对数据框进行排序,但老实说,我并不完全相信它对于 groupby 中具有更复杂组的大数据会按预期工作。使用转换我会感觉更舒服,否则,我认为通过索引将结果合并回 df 更可靠(假设我们有一个唯一的索引)。

如果我尝试对变换使用相同的函数:

df.groupby('D').transform(customFunc)

然后我得到一个错误:KeyError: 'A'

groupby.apply为了检查使用and时引擎盖下发生的事情groupby.transform,我执行了以下操作:

# Select the target-group
grp = df.groupby('D')

grp.apply(lambda x: type(x))

D
grp_1    (<class 'pandas.core.frame.DataFrame'>, 3)
grp_2    (<class 'pandas.core.frame.DataFrame'>, 3)
grp_3    (<class 'pandas.core.frame.DataFrame'>, 3)
dtype: object

grp.transform(lambda x: type(x))
                                     A                                    B                                    C  
0  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
1  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
2  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
3  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
4  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
5  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
6  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
7  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  
8  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0>  <property object at 0x7f7dbde619f0> 

如您所见,apply将子数据框作为组提供给我们,而我不知道确切transform提供了什么(这是我第一次面对财产)。我还做了进一步的测试:

# Another trials
grp.transform(lambda x: x.shape) # ValueError
grp.transform(lambda x: x['A']) # KeyError
grp.transform(lambda x: x.loc[0]) # KeyError
grp.transform(lambda x: x.iloc[0]) # works (every value get the first value; similar to 'first')

似乎.iloc[]我可以独立访问每列的值,但我仍然不知道如何访问其中的列transform(如果可能的话)。

所以,我最后的问题:

标签: pythonpandaspandas-groupby

解决方案


是否可以访问 groupby.transform 中的列名以跨列执行计算?

不可能,.groupby.transform分别处理每一列,所以不能“看到”其他列,如groupby.apply.

如果使用,您可以看到它print

print (df.groupby('D').transform(lambda x: print(x)))
2    0.980764
5    0.737995
8    0.722443
Name: A, dtype: float64
2    0.684830
5    0.182492
8    0.322959
Name: B, dtype: float64
2    0.480932
5    0.175452
8    0.361789
Name: C, dtype: float64

如果不是,将输出从应用放回数据帧的最佳(可靠)方法是什么?

如果函数不聚合值:

def customFunc(grp):
    return (grp['A'] - grp['B']) * grp['C']

df['new'] = df.groupby('D').apply(customFunc).rename('new').reset_index(level=0, drop=True)

print (df)
          A         B         C      D       new
0  0.696469  0.286139  0.226851  grp_1  0.093084
1  0.551315  0.719469  0.423106  grp_2 -0.071147
2  0.980764  0.684830  0.480932  grp_3  0.142324
3  0.392118  0.343178  0.729050  grp_1  0.035679
4  0.438572  0.059678  0.398044  grp_2  0.150817
5  0.737995  0.182492  0.175452  grp_3  0.097464
6  0.531551  0.531828  0.634401  grp_1 -0.000175
7  0.849432  0.724455  0.611024  grp_2  0.076364
8  0.722443  0.322959  0.361789  grp_3  0.144529

所以工作一样:

df['new'] = (df['A'] - df['B']) * df['C']

print (df)
         A         B         C      D       new
0  0.696469  0.286139  0.226851  grp_1  0.093084
1  0.551315  0.719469  0.423106  grp_2 -0.071147
2  0.980764  0.684830  0.480932  grp_3  0.142324
3  0.392118  0.343178  0.729050  grp_1  0.035679
4  0.438572  0.059678  0.398044  grp_2  0.150817
5  0.737995  0.182492  0.175452  grp_3  0.097464
6  0.531551  0.531828  0.634401  grp_1 -0.000175
7  0.849432  0.724455  0.611024  grp_2  0.076364
8  0.722443  0.322959  0.361789  grp_3  0.144529

如果使用函数聚合值DataFrame.joinSeries.map使用一列进行分组:

def customFunc(grp):
    return ((grp['A'] - grp['B']) * grp['C']).mean()

df = df.join(df.groupby('D').apply(customFunc).rename('new'), on='D')

def customFunc(grp):
    return ((grp['A'] - grp['B']) * grp['C']).mean()

df['new'] = df['D'].map(df.groupby('D').apply(customFunc))


print (df)
       A         B         C      D       new
0  0.696469  0.286139  0.226851  grp_1  0.042863
1  0.551315  0.719469  0.423106  grp_2  0.052011
2  0.980764  0.684830  0.480932  grp_3  0.128106
3  0.392118  0.343178  0.729050  grp_1  0.042863
4  0.438572  0.059678  0.398044  grp_2  0.052011
5  0.737995  0.182492  0.175452  grp_3  0.128106
6  0.531551  0.531828  0.634401  grp_1  0.042863
7  0.849432  0.724455  0.611024  grp_2  0.052011
8  0.722443  0.322959  0.361789  grp_3  0.128106

或更改功能:

def customFunc(grp):
    grp['new'] = ((grp['A'] - grp['B']) * grp['C']).mean()
    return grp
    
df = df.groupby('D').apply(customFunc)

print (df)
          A         B         C      D       new
0  0.696469  0.286139  0.226851  grp_1  0.042863
1  0.551315  0.719469  0.423106  grp_2  0.052011
2  0.980764  0.684830  0.480932  grp_3  0.128106
3  0.392118  0.343178  0.729050  grp_1  0.042863
4  0.438572  0.059678  0.398044  grp_2  0.052011
5  0.737995  0.182492  0.175452  grp_3  0.128106
6  0.531551  0.531828  0.634401  grp_1  0.042863
7  0.849432  0.724455  0.611024  grp_2  0.052011
8  0.722443  0.322959  0.361789  grp_3  0.128106

推荐阅读