如何通过多列功能对熊猫行进行分组

时间:2018-10-24 03:43:51

标签: python pandas pandas-groupby

我有一个数据框,其中记录了建筑物屋顶表面的特征,因此每座建筑物都有多个平面,并带有面积和形式描述。例如

df=pd.DataFrame([[1000, 12, 'slope'],
                [1000, 10, 'flat'],
                [1001, 10, 'slope'],
                [1001, 15, 'flat'],
                [1001, 7, 'slope']],
               index = [1,2,3,4,5],
               columns=['building_id', 'area', 'form'],
               )
df
building_id     area    form
1   1000    12  slope
2   1000    10  flat
3   1001    10  slope
4   1001    15  flat
5   1001    7   slope

我想合并各行,以便每栋建筑物都有一排,总的屋顶面积和主要的屋顶形式-即具有该建筑物最大面积的形式,而不是出现频率最高的形式:

df_out
building_id     area    form
    1   1000    22  slope
    2   1001    32  slope

我需要这样的东西:

group_functions={'area' : ['sum'],
                 'form' : lambda x: find_predominant(x)}
df_out = df.groupby('building_id').agg(group_functions)

但是find_predominant必须是areaform的函数:它返回字符串'flat''slope',具体取决于哪个字符串最大building_id的区域。

函数find_predominant是什么?还是什么脚本会产生相同的效果?

2 个答案:

答案 0 :(得分:3)

我的建议是计算总和并分别调用find_predomonant函数,因为这将需要调用apply

g = df.groupby('building_id')
area = g['area'].sum()
form = g.apply(find_predominant) 

df_out = pd.concat([area, form], axis=1)

现在,要使此方法起作用,请认识到find_predominant应该接受一个DataFrame并适当地访问“区域”和“表单”列。

def find_predominant(df):
    ar = df['area']
    fm = df['form']
    ... # Do something with ar and fm

    return result

这可能需要也可能不需要重构。


编辑:好的,所以您不知道该功能是什么。在这种情况下,让我们摆脱它。

尝试一下。

area = df.groupby('building_id')['area'].sum()
form = (df.groupby(['building_id', 'form'])['area']
          .sum()
          .groupby(level=0)
          .idxmax()
          .str[1])
form.name = 'form'

df_out = pd.concat([area, form], axis=1).reset_index()
print(df_out)
   building_id  area   form
0         1000    22  slope
1         1001    32  slope

这将选择与每个building_id拥有最大面积(按总和)的表单相对应的形式。

如果不需要以最大和为单位的表单,而您只是想要以最大面积为表单,则解决方案会简化。

g = df.groupby('building_id')['area']
area = g.sum()
form = (df.set_index('building_id')
          .iloc[g.idxmax(), df.columns.get_loc('form') - 1])

df_out = pd.concat([area, form], axis=1).reset_index()
print(df_out)
   building_id  area   form
0         1000    22   flat
1         1001    32  slope

答案 1 :(得分:2)

您可以使用sort_values并在agg之后分配值

(df.groupby(['building_id','form'])['area']
   .sum()
   .sort_values()
   .reset_index(level=1)
   .groupby(level=0)
   .agg({'form':'last','area':'sum'}))

              form  area
building_id             
1000         slope    22
1001         slope    32