使用groupby并应用于向每个组添加列

时间:2016-03-15 21:11:22

标签: python pandas transform apply

我有一个DataFrame,其中多索引作为列。我想按级别1进行分组并应用生成新列的函数。我希望将此计算列添加到每个组,因此我的数据框将为每个组添加新列。

我做了一个小的虚拟脚本和函数来复制我想做的事情。

import pandas as pd
import numpy as np

columns = [('A','julian'),('A','geoffrey'),
       ('B','julian'),('B','geoffrey'),
       ('C','julian'),('C','geoffrey')]

columns = pd.MultiIndex.from_tuples(columns)

dataframe = pd.DataFrame(data=np.random.rand(10,6),columns=columns)

def addColumn(inputDF):
   group = inputDF.columns[0][1]
   inputDF['sum', group] = inputDF.sum(axis=1)
   return inputDF

newColumnsDataframe = dataframe.groupby(level=1, axis=1).apply(addColumn) 

原始数据框如下所示:

      A                   B                   C          
    julian  geoffrey    julian  geoffrey    julian  geoffrey
 0  0.204082  0.073676  0.795725  0.279702  0.258185  0.258112
 1  0.263235  0.096733  0.507324  0.541198  0.525919  0.757652
 2  0.196243  0.028613  0.653408  0.364365  0.174911  0.924733
 3  0.528785  0.831569  0.654160  0.738029  0.940831  0.294473
 4  0.853517  0.263250  0.803087  0.855270  0.701937  0.264698
 5  0.239797  0.069519  0.943544  0.374411  0.189361  0.846647
 6  0.980734  0.290414  0.850097  0.873785  0.903645  0.118713
 7  0.591942  0.088387  0.566298  0.062140  0.568482  0.872064
 8  0.818167  0.061483  0.282050  0.008404  0.449198  0.658370
 9  0.217424  0.427602  0.471933  0.171458  0.390549  0.234426

结果数据框应如下所示(我分别构造了和DataFrame并连接了两个数据帧以实现此结果):

      A         B         C       sum         A         B         C  \
   geoffrey  geoffrey  geoffrey  geoffrey    julian    julian    julian   
0  0.073676  0.279702  0.258112  0.611491  0.204082  0.795725  0.258185   
1  0.096733  0.541198  0.757652  1.395584  0.263235  0.507324  0.525919   
2  0.028613  0.364365  0.924733  1.317710  0.196243  0.653408  0.174911   
3  0.831569  0.738029  0.294473  1.864071  0.528785  0.654160  0.940831   
4  0.263250  0.855270  0.264698  1.383219  0.853517  0.803087  0.701937   
5  0.069519  0.374411  0.846647  1.290578  0.239797  0.943544  0.189361   
6  0.290414  0.873785  0.118713  1.282912  0.980734  0.850097  0.903645   
7  0.088387  0.062140  0.872064  1.022590  0.591942  0.566298  0.568482   
8  0.061483  0.008404  0.658370  0.728257  0.818167  0.282050  0.449198   
9  0.427602  0.171458  0.234426  0.833486  0.217424  0.471933  0.390549   

    sum  
   julian  
0  1.257992  
1  1.296478  
2  1.024561  
3  2.123776  
4  2.358542  
5  1.372703  
6  2.734476  
7  1.726721  
8  1.549415  
9  1.079906  

上面脚本中的方法基于对我有意义的内容以及其他人在网上撰写的关于做这类事情的内容。但是,newColumnsDataframe仍然只有6列,而不是8列(每个名称都添加一列)。

我确实注意到当我按level = 0(因此使用A,B或C)进行分组并使用transform(但是当我在此级别上使用apply时不是这样),newColumnsDataframe确实有9列,添加了一个和列每组。请参阅以下代码:

import pandas as pd
import numpy as np

columns = [('A','julian'),('A','geoffrey'),
       ('B','julian'),('B','geoffrey'),
       ('C','julian'),('C','geoffrey')]

columns = pd.MultiIndex.from_tuples(columns)

dataframe = pd.DataFrame(data=np.random.rand(10,6),columns=columns)

def addColumn(inputDF):
    group = inputDF.columns[0][1]
    inputDF[group, 'sum'] = inputDF.sum(axis=1)
    return inputDF

newColumnsDataframe = dataframe.groupby(level=0, axis=1).transform(addColumn)

我始终理解,转换适用于组内的每一列,而apply作为整个数据帧在组中运行。这似乎与此相矛盾。 我也注意到,当我按level = 1进行分组并使用transform而不是apply时,会抛出以下错误:

ValueError: Length mismatch: Expected axis has 10 elements, new values have 6 elements

我对发生的事情感到非常困惑。当我在level = 0上使用transform和group时,有没有人知道为什么这个可以工作。为什么在我执行相同但在level = 1上的组时出现错误。为什么在EITHER级别上分组并应用该函数不会在我的最终数据帧中添加列?提前谢谢!

(PS:这不是我用来添加列的实际DataFrame或函数,只是一个更简单的插图)

1 个答案:

答案 0 :(得分:2)

有点乱,但是单行:

(df.join(pd.concat({'sum': df.groupby(level=1, axis=1).sum()}, axis=1))
   .sortlevel(level=1, axis=1))

为我制作这个:

          A         B         C       sum         A         B         C  \
   geoffrey  geoffrey  geoffrey  geoffrey    julian    julian    julian   
0  0.073676  0.279702  0.258112  0.611490  0.204082  0.795725  0.258185   
1  0.096733  0.541198  0.757652  1.395583  0.263235  0.507324  0.525919   
2  0.028613  0.364365  0.924733  1.317711  0.196243  0.653408  0.174911   
3  0.831569  0.738029  0.294473  1.864071  0.528785  0.654160  0.940831   
4  0.263250  0.855270  0.264698  1.383218  0.853517  0.803087  0.701937   
5  0.069519  0.374411  0.846647  1.290577  0.239797  0.943544  0.189361   
6  0.290414  0.873785  0.118713  1.282912  0.980734  0.850097  0.903645   
7  0.088387  0.062140  0.872064  1.022591  0.591942  0.566298  0.568482   
8  0.061483  0.008404  0.658370  0.728257  0.818167  0.282050  0.449198   
9  0.427602  0.171458  0.234426  0.833486  0.217424  0.471933  0.390549   

        sum  
     julian  
0  1.257992  
1  1.296478  
2  1.024562  
3  2.123776  
4  2.358541  
5  1.372702  
6  2.734476  
7  1.726722  
8  1.549415  
9  1.079906 

我刚才说“这是我的df,首先按人物名称分组,然后将其加总,然后将这两个相加的列连接回原始df,然后使用{{1}按sortlevellevel=1排序。“

因此,'sum'出现在axis=1列之后的唯一原因仅仅是因为C字母位于s之后。如果您有一个名为C的列,则无效。不确定这是否重要。

以下是我用于娱乐目的的x

df

<强>编辑:

这是另一种方法:

df = pd.DataFrame({
      ('C', 'julian'): [0.258185, 0.52591899999999991, 0.17491099999999998, 0.94083099999999997, 0.70193700000000003, 0.189361, 0.90364500000000003, 0.56848199999999993, 0.44919799999999993, 0.39054899999999998],
      ('B', 'geoffrey'): [0.27970200000000001, 0.54119799999999996, 0.36436499999999999, 0.73802900000000005, 0.85527000000000009, 0.37441099999999999, 0.87378500000000003, 0.062140000000000001, 0.008404, 0.171458], 
      ('A', 'julian'): [0.20408199999999999, 0.263235, 0.196243, 0.52878500000000006, 0.85351699999999997, 0.23979699999999998, 0.98073399999999999, 0.59194199999999997, 0.81816699999999998, 0.21742399999999998], 
      ('B', 'julian'): [0.79572500000000002, 0.507324, 0.65340799999999999, 0.65416000000000007, 0.803087, 0.94354400000000005, 0.85009699999999988, 0.56629799999999997, 0.28205000000000002, 0.47193299999999999], 
      ('A', 'geoffrey'): [0.073676000000000005, 0.096733, 0.028613, 0.831569, 0.26324999999999998, 0.069519000000000011, 0.29041400000000001, 0.088387000000000007, 0.061483000000000003, 0.42760200000000004], 
      ('C', 'geoffrey'): [0.25811200000000001, 0.75765199999999999, 0.92473300000000003, 0.29447299999999998, 0.26469799999999999, 0.84664699999999993, 0.11871300000000001, 0.87206399999999995, 0.65837000000000001, 0.23442600000000002]},
      columns=pd.MultiIndex.from_tuples([('A','julian'),('A','geoffrey'), ('B','julian'),('B','geoffrey'), ('C','julian'),('C','geoffrey')]))

sum_columns = [('sum', name) for name in df.columns.levels[1].tolist()] df[sum_columns] = df.groupby(axis=1, level=1).sum() df = df.sortlevel(level=1, axis=1) - 看起来像sum_columns

[('sum', 'geoffrey'), ('sum', 'julian')]为第1级的每个名称创建一个新的“和”列。

如果希望在名称旁边加上总和列,请使用df[sum_columns]