Pandas-按多个列分组和聚合

4

我正在尝试对多个列进行groupby聚合值。我来自于R/dplyr的世界,使用group_by/summarize通常可以在一行代码中实现我想要的内容。我正在尝试寻找使用pandas实现同样优雅的方式。

考虑下面的输入数据集。我想按州( state )聚合并计算列v1, 其中 v1 = sum(n1)/sum(d1) by state

使用dplyr的r-code如下:

input %>% group_by(state) %>% 
  summarise(v1=sum(n1)/sum(d1),
            v2=sum(n2)/sum(d2))

有没有一种优雅的方法在Python中实现这个功能?我在stackoverflow网站上找到了一个略显冗长的方法来获取我想要的结果,链接地址为这里。 需要将修改后的Python代码从链接复制过来。

In [14]: s = mn.groupby('state', as_index=False).sum()

In [15]: s['v1'] = s['n1'] / s['d1']

In [16]: s['v2'] = s['n2'] / s['d2']
In [17]: s[['state', 'v1', 'v2']]

输入数据集

state n1    n2     d1  d2
CA   100   1000    1   2
FL   200   2000    2   4
CA   300   3000    3   6
AL   400   4000    4   8
FL   500   5000    5   2
NY   600   6000    6   4
CA   700   7000    7   6

输出

state   v1           v2
AL      100   500.000000
CA      100   500.000000
NY      100  1500.000000
CA      100  1166.666667
FL      100  1166.666667
4个回答

1

这是与您在R中所做的等效方式:

>>> from datar.all import f, tribble, group_by, summarise, sum
>>> 
>>> input = tribble(
...     f.state, f.n1,    f.n2,     f.d1,  f.d2,
...     "CA",    100,     1000,     1,     2,
...     "FL",    200,     2000,     2,     4,
...     "CA",    300,     3000,     3,     6,
...     "AL",    400,     4000,     4,     8,
...     "FL",    500,     5000,     5,     2,
...     "NY",    600,     6000,     6,     4,
...     "CA",    700,     7000,     7,     6,
... )
>>> 
>>> input >> group_by(f.state) >> \
...   summarise(v1=sum(f.n1)/sum(f.d1),
...             v2=sum(f.n2)/sum(f.d2))
     state        v1           v2
  <object> <float64>    <float64>
0       AL     100.0   500.000000
1       CA     100.0   785.714286
2       FL     100.0  1166.666667
3       NY     100.0  1500.000000

我是datar包的作者。


1
另一种选择是使用pipe函数,其中groupby对象是可重复使用的:
(df.groupby('state')
   .pipe(lambda df: pd.DataFrame({'v1' : df.n1.sum() / df.d1.sum(), 
                                  'v2' : df.n2.sum() / df.d2.sum()})
        )
) 
          v1           v2
state                    
AL     100.0   500.000000
CA     100.0   785.714286
FL     100.0  1166.666667
NY     100.0  1500.000000

另一种选择是在分组之前将列转换为MultiIndex:

temp = temp = df.set_index('state')
temp.columns = temp.columns.str.split('(\d)', expand=True).droplevel(-1)

(temp.groupby('state')
     .sum()
     .pipe(lambda df: df.n /df.d)
     .add_prefix('v')
)
 
          v1           v2
state                    
AL     100.0   500.000000
CA     100.0   785.714286
FL     100.0  1166.666667
NY     100.0  1500.000000

还有一种方法,仍然使用MultiIndex选项,同时避免使用groupby:

# keep the index, necessary for unstacking later
temp = df.set_index('state', append=True) 

# convert the columns to a MultiIndex
temp.columns = temp.columns.map(tuple)

# this works because the index is unique
(temp.unstack('state')
     .sum()
     .unstack([0,1])
     .pipe(lambda df: df.n / df.d)
     .add_prefix('v')
) 
          v1           v2
state                    
AL     100.0   500.000000
CA     100.0   785.714286
FL     100.0  1166.666667
NY     100.0  1500.000000


1

使用DataFrame.assignDataFrame.reindex可能是一种解决方案:

df = (mn.groupby('state', as_index=False)
        .sum()
        .assign(v1 = lambda x: x['n1'] / x['d1'], v2 = lambda x: x['n2'] / x['d2'])
        .reindex(['state', 'v1', 'v2'], axis=1))

print (df)
  state     v1           v2
0    AL  100.0   500.000000
1    CA  100.0   785.714286
2    FL  100.0  1166.666667
3    NY  100.0  1500.000000

另一个示例使用 GroupBy.apply 和自定义 lambda 函数:

df = (mn.groupby('state')
        .apply(lambda x: x[['n1','n2']].sum() / x[['d1','d2']].sum().values)
        .reset_index()  
        .rename(columns={'n1':'v1', 'n2':'v2'})
      )
print (df)
  state     v1           v2
0    AL  100.0   500.000000
1    CA  100.0   785.714286
2    FL  100.0  1166.666667
3    NY  100.0  1500.000000

1

另一种解决方案:

def func(x):
    u = x.sum()
    return pd.Series({'v1':u['n1']/u['d1'],
                      'v2':u['n2']/u['d2']})

df.groupby('state').apply(func)

输出:

         v1     v2
state       
AL      100.0   500.000000
CA      100.0   785.714286
FL      100.0   1166.666667
NY      100.0   1500.000000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接