转换 pandas 个 DataFrames 组 - 完全转换,而不仅仅是一个系列

Transform pandas DataFrames groups - completely, not just a Series

我想转换 pandas' DataFrame 中的每个组。按组,我指的不是 DataFrame 的单个列,而是整个组。这是我的意思的一个例子:

df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar', 'foo', 'bar'],
                   'B' : ['one', 'one', 'two', 'two', 'one', 'two'],
                   'C' : [    1,     5,     5,     2,     6,     5],
                   'D' : [  2.0,    5.,    8.,    1.,     2.,   9.]})

def transformation_function(group: pd.DataFrame) -> pd.DataFrame:
    group = group.copy()
    if all(group.B == 'one'):
        group.D[group.C>2] = group.D[group.C>2] + 1
    else:
        group.A = 'new'
    return group

df.groupby('B').transform(transformation_function)

我期望的地方

     pd.DataFrame({'A' : ['foo', 'bar', 'new', 'new', 'foo', 'new'],
                   'B' : ['one', 'one', 'two', 'two', 'one', 'two'],
                   'C' : [    1,     5,     5,     2,     5,     5],
                   'D' : [  2.0,    6.,    8.,    1.,    3.,    9.]})

因此。现在,我得到了

AttributeError: 'Series' object has no attribute 'B'

这对我来说没有意义,因为 documentation 明确指出

Call function producing a like-indexed DataFrame on each group and return a DataFrame having the same indexes as the original object filled with the transformed values

我知道所有示例都是基于系列的,例如 df.groupby('B')['a_column_name'].transform(change_fct),但是如果转换函数需要所有列,那么这样的事情是不可能的。

那么,如何使用 pandas' 方法链获得我期望的结果?

在您的解决方案中,transform 函数分别处理每一列,因此不可能 select 按名称列。需要 GroupBy.apply:

df = df.groupby('B').apply(transformation_function)
    
print (df)
         A    B  C    D
B                      
one 0  foo  one  1  2.0
    1  bar  one  5  6.0
    4  foo  one  6  3.0
two 2  new  two  5  8.0
    3  new  two  2  1.0
    5  new  two  5  9.0

处理组如何可能参见例如通过 print:

df.groupby('B').transform(lambda x: print (x))
0    foo
1    bar
4    foo
Name: A, dtype: object
0    1
1    5
4    6
Name: C, dtype: int64
0    2.0
1    5.0
4    2.0
Name: D, dtype: float64
     A  C    D
0  foo  1  2.0
1  bar  5  5.0
4  foo  6  2.0
2    foo
3    bar
5    bar
Name: A, dtype: object
2    5
3    2
5    5
Name: C, dtype: int64
2    8.0
3    1.0
5    9.0
Name: D, dtype: float64
     A  C    D
2  foo  5  8.0
3  bar  2  1.0
5  bar  5  9.0

df.groupby('B').apply(lambda x: print (x))

     A    B  C    D
0  foo  one  1  2.0
1  bar  one  5  5.0
4  foo  one  6  2.0
     A    B  C    D
2  foo  two  5  8.0
3  bar  two  2  1.0
5  bar  two  5  9.0