pandas 等价于 dplyr summarize/aggregate 的多个函数是多少?
What is the pandas equivalent of dplyr summarize/aggregate by multiple functions?
我在从 R 过渡到 pandas 时遇到问题,其中 dplyr
包可以轻松分组并执行多个摘要。
请帮助改进我现有的 Python pandas 多个聚合代码:
import pandas as pd
data = pd.DataFrame(
{'col1':[1,1,1,1,1,2,2,2,2,2],
'col2':[1,2,3,4,5,6,7,8,9,0],
'col3':[-1,-2,-3,-4,-5,-6,-7,-8,-9,0]
}
)
result = []
for k,v in data.groupby('col1'):
result.append([k, max(v['col2']), min(v['col3'])])
print pd.DataFrame(result, columns=['col1', 'col2_agg', 'col3_agg'])
问题:
- 太冗长
- 可能可以优化和提高效率。 (我将
for-loop groupby
实现重写为 groupby.agg
并且性能得到了巨大的提升)。
在 R 中,等效代码为:
data %>% groupby(col1) %>% summarize(col2_agg=max(col2), col3_agg=min(col3))
更新:@ayhan 解决了我的问题,这是一个后续问题,我将在此处 post 而不是评论:
Q2) groupby().summarize(newcolumn=max(col2 * col3))
的等价物是什么,即函数是 2+ 列的复合函数的 aggregation/summarization?
相当于
df %>% groupby(col1) %>% summarize(col2_agg=max(col2), col3_agg=min(col3))
是
df.groupby('col1').agg({'col2': 'max', 'col3': 'min'})
哪个return
col2 col3
col1
1 5 -5
2 9 -9
returning 对象是一个 pandas.DataFrame,索引名为 col1
,列名为 col2
和 col3
。默认情况下,当您对数据进行分组时,pandas 将分组列设置为索引以进行高效访问和修改。但是,如果您不想这样做,有两种选择可以将 col1
设置为列。
通过 as_index=False
:
df.groupby('col1', as_index=False).agg({'col2': 'max', 'col3': 'min'})
呼叫reset_index
:
df.groupby('col1').agg({'col2': 'max', 'col3': 'min'}).reset_index()
两者都屈服
col1 col2 col3
1 5 -5
2 9 -9
您还可以将多个函数传递给 groupby.agg
。
agg_df = df.groupby('col1').agg({'col2': ['max', 'min', 'std'],
'col3': ['size', 'std', 'mean', 'max']})
这也是一个 DataFrame return,但现在它有一个用于列的 MultiIndex。
col2 col3
max min std size std mean max
col1
1 5 1 1.581139 5 1.581139 -3 -1
2 9 0 3.535534 5 3.535534 -6 0
MultiIndex 用于选择和分组非常方便。以下是一些示例:
agg_df['col2'] # select the second column
max min std
col1
1 5 1 1.581139
2 9 0 3.535534
agg_df[('col2', 'max')] # select the maximum of the second column
Out:
col1
1 5
2 9
Name: (col2, max), dtype: int64
agg_df.xs('max', axis=1, level=1) # select the maximum of all columns
Out:
col2 col3
col1
1 5 -1
2 9 0
早些时候(在 version 0.20.0 之前)可以使用字典来重命名 agg
调用中的列。例如
df.groupby('col1')['col2'].agg({'max_col2': 'max'})
将return第二列的最大值设为max_col2
:
max_col2
col1
1 5
2 9
但是,它已被弃用,取而代之的是重命名方法:
df.groupby('col1')['col2'].agg(['max']).rename(columns={'max': 'col2_max'})
col2_max
col1
1 5
2 9
对于像上面定义的 agg_df
这样的 DataFrame,它可能会变得冗长。在这种情况下,您可以使用重命名函数来展平这些级别:
agg_df.columns = ['_'.join(col) for col in agg_df.columns]
col2_max col2_min col2_std col3_size col3_std col3_mean col3_max
col1
1 5 1 1.581139 5 1.581139 -3 -1
2 9 0 3.535534 5 3.535534 -6 0
对于像groupby().summarize(newcolumn=max(col2 * col3))
这样的操作,您仍然可以通过先添加一个带有assign
的新列来使用agg。
df.assign(new_col=df.eval('col2 * col3')).groupby('col1').agg('max')
col2 col3 new_col
col1
1 5 -1 -1
2 9 0 0
这个 return 是旧列和新列的最大值,但一如既往,您可以将其切分。
df.assign(new_col=df.eval('col2 * col3')).groupby('col1')['new_col'].agg('max')
col1
1 -1
2 0
Name: new_col, dtype: int64
使用 groupby.apply
这会更短:
df.groupby('col1').apply(lambda x: (x.col2 * x.col3).max())
col1
1 -1
2 0
dtype: int64
但是,groupby.apply
将其视为自定义函数,因此未对其进行矢量化。到目前为止,我们传递给 agg
的函数('min'、'max'、'min'、'size' 等)是矢量化的,这些是优化的别名职能。您可以将 df.groupby('col1').agg('min')
替换为 df.groupby('col1').agg(min)
、df.groupby('col1').agg(np.min)
或 df.groupby('col1').min()
,它们都将执行相同的功能。使用自定义函数时,您将看不到同样的效率。
最后,从 0.20 版本开始,agg
可以直接在 DataFrames 上使用,而无需先分组。请参阅示例 。
在此处查看 Pandas 文档给出的并排比较:http://pandas.pydata.org/pandas-docs/stable/comparison_with_r.html#grouping-and-summarizing
R 的 dplyr
gdf <- group_by(df, col1)
summarise(gdf, avg=mean(col1, na.rm=TRUE))
Pandas
gdf = df.groupby('col1')
df.groupby('col1').agg({'col1': 'mean'})
使用 datar
:
无需学习 pandas 的 API 即可轻松将 R 代码转换为 python 代码
>>> from datar import f
>>> from datar.tibble import tibble
>>> from datar.dplyr import group_by, summarize
>>> from datar.base import min, max
>>> data = tibble(
... col1=[1,1,1,1,1,2,2,2,2,2],
... col2=[1,2,3,4,5,6,7,8,9,0],
... col3=[-1,-2,-3,-4,-5,-6,-7,-8,-9,0]
... )
>>> data >> group_by(f.col1) >> summarize(col2_agg=max(f.col2), col3_agg=min(f.col3))
col1 col2_agg col3_agg
0 1 5 -5
1 2 9 -9
我是包的作者。有问题欢迎提issue
我在从 R 过渡到 pandas 时遇到问题,其中 dplyr
包可以轻松分组并执行多个摘要。
请帮助改进我现有的 Python pandas 多个聚合代码:
import pandas as pd
data = pd.DataFrame(
{'col1':[1,1,1,1,1,2,2,2,2,2],
'col2':[1,2,3,4,5,6,7,8,9,0],
'col3':[-1,-2,-3,-4,-5,-6,-7,-8,-9,0]
}
)
result = []
for k,v in data.groupby('col1'):
result.append([k, max(v['col2']), min(v['col3'])])
print pd.DataFrame(result, columns=['col1', 'col2_agg', 'col3_agg'])
问题:
- 太冗长
- 可能可以优化和提高效率。 (我将
for-loop groupby
实现重写为groupby.agg
并且性能得到了巨大的提升)。
在 R 中,等效代码为:
data %>% groupby(col1) %>% summarize(col2_agg=max(col2), col3_agg=min(col3))
更新:@ayhan 解决了我的问题,这是一个后续问题,我将在此处 post 而不是评论:
Q2) groupby().summarize(newcolumn=max(col2 * col3))
的等价物是什么,即函数是 2+ 列的复合函数的 aggregation/summarization?
相当于
df %>% groupby(col1) %>% summarize(col2_agg=max(col2), col3_agg=min(col3))
是
df.groupby('col1').agg({'col2': 'max', 'col3': 'min'})
哪个return
col2 col3
col1
1 5 -5
2 9 -9
returning 对象是一个 pandas.DataFrame,索引名为 col1
,列名为 col2
和 col3
。默认情况下,当您对数据进行分组时,pandas 将分组列设置为索引以进行高效访问和修改。但是,如果您不想这样做,有两种选择可以将 col1
设置为列。
通过
as_index=False
:df.groupby('col1', as_index=False).agg({'col2': 'max', 'col3': 'min'})
呼叫
reset_index
:df.groupby('col1').agg({'col2': 'max', 'col3': 'min'}).reset_index()
两者都屈服
col1 col2 col3
1 5 -5
2 9 -9
您还可以将多个函数传递给 groupby.agg
。
agg_df = df.groupby('col1').agg({'col2': ['max', 'min', 'std'],
'col3': ['size', 'std', 'mean', 'max']})
这也是一个 DataFrame return,但现在它有一个用于列的 MultiIndex。
col2 col3
max min std size std mean max
col1
1 5 1 1.581139 5 1.581139 -3 -1
2 9 0 3.535534 5 3.535534 -6 0
MultiIndex 用于选择和分组非常方便。以下是一些示例:
agg_df['col2'] # select the second column
max min std
col1
1 5 1 1.581139
2 9 0 3.535534
agg_df[('col2', 'max')] # select the maximum of the second column
Out:
col1
1 5
2 9
Name: (col2, max), dtype: int64
agg_df.xs('max', axis=1, level=1) # select the maximum of all columns
Out:
col2 col3
col1
1 5 -1
2 9 0
早些时候(在 version 0.20.0 之前)可以使用字典来重命名 agg
调用中的列。例如
df.groupby('col1')['col2'].agg({'max_col2': 'max'})
将return第二列的最大值设为max_col2
:
max_col2
col1
1 5
2 9
但是,它已被弃用,取而代之的是重命名方法:
df.groupby('col1')['col2'].agg(['max']).rename(columns={'max': 'col2_max'})
col2_max
col1
1 5
2 9
对于像上面定义的 agg_df
这样的 DataFrame,它可能会变得冗长。在这种情况下,您可以使用重命名函数来展平这些级别:
agg_df.columns = ['_'.join(col) for col in agg_df.columns]
col2_max col2_min col2_std col3_size col3_std col3_mean col3_max
col1
1 5 1 1.581139 5 1.581139 -3 -1
2 9 0 3.535534 5 3.535534 -6 0
对于像groupby().summarize(newcolumn=max(col2 * col3))
这样的操作,您仍然可以通过先添加一个带有assign
的新列来使用agg。
df.assign(new_col=df.eval('col2 * col3')).groupby('col1').agg('max')
col2 col3 new_col
col1
1 5 -1 -1
2 9 0 0
这个 return 是旧列和新列的最大值,但一如既往,您可以将其切分。
df.assign(new_col=df.eval('col2 * col3')).groupby('col1')['new_col'].agg('max')
col1
1 -1
2 0
Name: new_col, dtype: int64
使用 groupby.apply
这会更短:
df.groupby('col1').apply(lambda x: (x.col2 * x.col3).max())
col1
1 -1
2 0
dtype: int64
但是,groupby.apply
将其视为自定义函数,因此未对其进行矢量化。到目前为止,我们传递给 agg
的函数('min'、'max'、'min'、'size' 等)是矢量化的,这些是优化的别名职能。您可以将 df.groupby('col1').agg('min')
替换为 df.groupby('col1').agg(min)
、df.groupby('col1').agg(np.min)
或 df.groupby('col1').min()
,它们都将执行相同的功能。使用自定义函数时,您将看不到同样的效率。
最后,从 0.20 版本开始,agg
可以直接在 DataFrames 上使用,而无需先分组。请参阅示例
在此处查看 Pandas 文档给出的并排比较:http://pandas.pydata.org/pandas-docs/stable/comparison_with_r.html#grouping-and-summarizing
R 的 dplyr
gdf <- group_by(df, col1)
summarise(gdf, avg=mean(col1, na.rm=TRUE))
Pandas
gdf = df.groupby('col1')
df.groupby('col1').agg({'col1': 'mean'})
使用 datar
:
>>> from datar import f
>>> from datar.tibble import tibble
>>> from datar.dplyr import group_by, summarize
>>> from datar.base import min, max
>>> data = tibble(
... col1=[1,1,1,1,1,2,2,2,2,2],
... col2=[1,2,3,4,5,6,7,8,9,0],
... col3=[-1,-2,-3,-4,-5,-6,-7,-8,-9,0]
... )
>>> data >> group_by(f.col1) >> summarize(col2_agg=max(f.col2), col3_agg=min(f.col3))
col1 col2_agg col3_agg
0 1 5 -5
1 2 9 -9
我是包的作者。有问题欢迎提issue