Python 数据帧上的Groupby值计数

Python 数据帧上的Groupby值计数,python,pandas,dataframe,crosstab,pandas-groupby,Python,Pandas,Dataframe,Crosstab,Pandas Groupby,我有以下数据帧: df = pd.DataFrame([ (1, 1, 'term1'), (1, 2, 'term2'), (1, 1, 'term1'), (1, 1, 'term2'), (2, 2, 'term3'), (2, 3, 'term1'), (2, 2, 'term1') ], columns=['id', 'group', 'term']) 我想按id和group对其进行分组,并计算此id、group对的每个术语的数

我有以下数据帧:

df = pd.DataFrame([
    (1, 1, 'term1'),
    (1, 2, 'term2'),
    (1, 1, 'term1'),
    (1, 1, 'term2'),
    (2, 2, 'term3'),
    (2, 3, 'term1'),
    (2, 2, 'term1')
], columns=['id', 'group', 'term'])
我想按
id
group
对其进行分组,并计算此id、group对的每个术语的数目

所以最后我会得到这样的结果:

我可以通过使用
df.iterrows()
在所有行上循环并创建一个新的数据帧来实现我想要的,但这显然是低效的。(如果有帮助的话,我事先知道所有术语的列表,共有10个)

看起来我必须按分组然后计算值,所以我尝试使用
df.groupby(['id',group']).value\u counts()
,它不起作用,因为它在groupby系列而不是数据帧上运行

无论如何,我可以在不循环的情况下实现这一点?

您可以使用:

另一个具有聚合的解决方案,通过以下方式重塑:

计时

df = pd.concat([df]*10000).reset_index(drop=True)

In [48]: %timeit (df.groupby(['id', 'group', 'term']).size().unstack(fill_value=0))
100 loops, best of 3: 12.4 ms per loop

In [49]: %timeit (df.groupby(['id', 'group', 'term'])['term'].size().unstack(fill_value=0))
100 loops, best of 3: 12.2 ms per loop
使用方法:

针对700K行DF的计时:

In [24]: df = pd.concat([df] * 10**5, ignore_index=True)

In [25]: df.shape
Out[25]: (700000, 3)

In [3]: %timeit df.groupby(['id', 'group', 'term'])['term'].size().unstack(fill_value=0)
1 loop, best of 3: 226 ms per loop

In [4]: %timeit df.pivot_table(index=['id','group'], columns='term', aggfunc='size', fill_value=0)
1 loop, best of 3: 236 ms per loop

In [5]: %timeit pd.crosstab([df.id, df.group], df.term)
1 loop, best of 3: 355 ms per loop

In [6]: %timeit df.groupby(['id','group','term'])['term'].size().unstack().fillna(0).astype(int)
1 loop, best of 3: 232 ms per loop

In [7]: %timeit df.groupby(['id', 'group', 'term']).size().unstack(fill_value=0)
1 loop, best of 3: 231 ms per loop
针对7M排DF的计时:

In [9]: df = pd.concat([df] * 10, ignore_index=True)

In [10]: df.shape
Out[10]: (7000000, 3)

In [11]: %timeit df.groupby(['id', 'group', 'term'])['term'].size().unstack(fill_value=0)
1 loop, best of 3: 2.27 s per loop

In [12]: %timeit df.pivot_table(index=['id','group'], columns='term', aggfunc='size', fill_value=0)
1 loop, best of 3: 2.3 s per loop

In [13]: %timeit pd.crosstab([df.id, df.group], df.term)
1 loop, best of 3: 3.37 s per loop

In [14]: %timeit df.groupby(['id','group','term'])['term'].size().unstack().fillna(0).astype(int)
1 loop, best of 3: 2.28 s per loop

In [15]: %timeit df.groupby(['id', 'group', 'term']).size().unstack(fill_value=0)
1 loop, best of 3: 1.89 s per loop

我使用
groupby
size

df.groupby(['id', 'group', 'term']).size().unstack(fill_value=0)


时机

1000000行


与其记住冗长的解决方案,不如选择pandas为您内置的解决方案:

df.groupby(['id', 'group', 'term']).count()

哇,你太棒了。你只花了3分钟(和我写一个循环的时间相同,写这个问题的时间也比我少)。如果您能写一些解释来解释这项工作的原因,我将不胜感激,但我很可能在几分钟内就能自己理解它。在您的情况下,
交叉表
透视表
更好,因为默认聚合函数是
len
(与
大小
相同)我认为这也是更快的解决方案<代码>交叉表使用第一个参数作为列的
索引
第二个
。给我一点时间,我尝试添加计时。但我认为最好是用解释。@jezrael thx,
size
也更快<代码>交叉表的效率出奇地低,我很惊讶
交叉表
如此懒惰;)@jezrael,
交叉表
使用
透视表
内部…)@piRSquared-您可以添加到计时
df.groupby(['id','group','term'])['term'].size().unstack(fill_value=0)
?对我来说似乎更快。谢谢。@piRSquared-我在更大的df中尝试,速度更快一些(0.2ms,也许是相同的;))我只是想用更大的样本更新计时:-)哇!pivot在更大范围内似乎同样有效。我必须记住这一点。我想给你+1,但我刚才已经给了。所以我们忘记了别名:)@ayhan,非常奇怪-这次使用
df.assign(one=np.one(len(df))).pivot\u表(index=['id','group'],columns='term',values='one',aggfunc=np.sum,fill\u value=0)的解决方案有点慢-
1循环,最佳3:2.55秒/循环
我认为这是因为您使用了
len
而不是“size”
len
是一个Python函数,但我们作为字符串传递的函数是优化C函数的别名。
In [9]: df = pd.concat([df] * 10, ignore_index=True)

In [10]: df.shape
Out[10]: (7000000, 3)

In [11]: %timeit df.groupby(['id', 'group', 'term'])['term'].size().unstack(fill_value=0)
1 loop, best of 3: 2.27 s per loop

In [12]: %timeit df.pivot_table(index=['id','group'], columns='term', aggfunc='size', fill_value=0)
1 loop, best of 3: 2.3 s per loop

In [13]: %timeit pd.crosstab([df.id, df.group], df.term)
1 loop, best of 3: 3.37 s per loop

In [14]: %timeit df.groupby(['id','group','term'])['term'].size().unstack().fillna(0).astype(int)
1 loop, best of 3: 2.28 s per loop

In [15]: %timeit df.groupby(['id', 'group', 'term']).size().unstack(fill_value=0)
1 loop, best of 3: 1.89 s per loop
df.groupby(['id', 'group', 'term']).size().unstack(fill_value=0)
df = pd.DataFrame(dict(id=np.random.choice(100, 1000000),
                       group=np.random.choice(20, 1000000),
                       term=np.random.choice(10, 1000000)))
df.groupby(['id', 'group', 'term']).count()