使用Pandas中的groupby函数,统计一个列中与另一个列进行比较的内容数量。

8
也许 groupby 不是正确的方法。看起来应该可以工作,但我没有看到结果... 我想要按照事件结果对其进行分组。以下是我的数据框 (df):
Status  Event
SUCCESS Run
SUCCESS Walk
SUCCESS Run
FAILED  Walk

这是我想要的结果:

Event   SUCCESS FAILED
Run     2       1
Walk    0       1

我正在尝试创建一个分组对象,但是我不知道如何调用它来显示我想要的内容。

grouped = df['Status'].groupby(df['Event'])

1
请注意@piRSquared的解决方案,与其他方案相比,它看起来更加整洁和快速。 - MaxU - stand with Ukraine
4个回答

10
请提供需要翻译的内容。
 pd.crosstab(df.Event, df.Status)

Status  FAILED  SUCCESS
Event                  
Run          0        2
Walk         1        1


len("df.groupby('Event').Status.value_counts().unstack().fillna(0)")
61

len("df.pivot_table(index='Event', columns='Status', aggfunc=len, fill_value=0)")
74

len("pd.crosstab(df.Event, df.Status)")
32

3
那个比较挺有趣的! :) - MaxU - stand with Ukraine
2
Python之禅,第三条。简洁胜于复杂。 - Merlin

10

我会这样做:

df.groupby('Event').Status.value_counts().unstack().fillna(0)

或者使用fill_value参数:

df.groupby('Event').Status.value_counts().unstack(fill_value=0)

在此输入图片描述


时序

在此输入图片描述


是的,你的解决方案更快速。 - MaxU - stand with Ukraine

9

另一种解决方案是使用pivot_table()方法:

In [5]: df.pivot_table(index='Event', columns='Status', aggfunc=len, fill_value=0)
Out[5]:
Status  FAILED  SUCCESS
Event
Run          0        2
Walk         1        1

针对700K个数据框的时间:

In [74]: df.shape
Out[74]: (700000, 2)

In [75]: # (c) Merlin

In [76]: %%timeit
   ....: pd.crosstab(df.Event, df.Status)
   ....:
1 loop, best of 3: 333 ms per loop

In [77]: # (c) piRSquared

In [78]: %%timeit
   ....: df.groupby('Event').Status.value_counts().unstack().fillna(0)
   ....:
1 loop, best of 3: 325 ms per loop

In [79]: # (c) MaxU

In [80]: %%timeit
   ....: df.pivot_table(index='Event', columns='Status',
   ....:                aggfunc=len, fill_value=0)
   ....:
1 loop, best of 3: 367 ms per loop

In [81]: # (c) ayhan

In [82]: %%timeit
   ....: (df.assign(ones = np.ones(len(df)))
   ....:    .pivot_table(index='Event', columns='Status',
   ....:                 aggfunc=np.sum, values = 'ones')
   ....: )
   ....:
1 loop, best of 3: 264 ms per loop

In [83]: # (c) Divakar

In [84]: %%timeit
   ....: unq1,ID1 = np.unique(df['Event'],return_inverse=True)
   ....: unq2,ID2 = np.unique(df['Status'],return_inverse=True)
   ....: # Get linear indices/tags corresponding to grouped headers
   ....: tag = ID1*(ID2.max()+1) + ID2
   ....: # Setup 2D Numpy array equivalent of expected Dataframe
   ....: out = np.zeros((len(unq1),len(unq2)),dtype=int)
   ....: unqID, count = np.unique(tag,return_counts=True)
   ....: np.put(out,unqID,count)
   ....: # Finally convert to Dataframe
   ....: df_out = pd.DataFrame(out,columns=unq2)
   ....: df_out.index = unq1
   ....:
1 loop, best of 3: 2.25 s per loop

结论:@ayhan的解决方案目前获胜:
(df.assign(ones = np.ones(len(df)))
   .pivot_table(index='Event', columns='Status', values = 'ones',
                aggfunc=np.sum, fill_value=0)
)

1
你能用sum而不是len测试透视表吗?我认为len会减慢它的速度。df.assign(ones = np.ones(len(df))).pivot_table(index='Event', columns='Status', aggfunc=np.sum, values = 'ones') - ayhan
2
我对交叉表格感到惊讶。因为它是专门为此设计的,所以我本来期望它是最快的。不过它的扩展性还是很好的。 - ayhan
1
@ayhan,刚刚检查了pandas的crosstab()实现 - 它在内部使用pivot_table(..., aggfunc=len)pivot_table(..., aggfunc=aggfunc)(如果指定了aggfunc);) - MaxU - stand with Ukraine
顺便说一下,df.pivot_table(index='Event', columns='Status', aggfunc='count', fill_value=0) 更快(可能是因为它不需要新列) :) - ayhan
有趣。我刚刚计时了,我确信它会起作用的。 - ayhan
显示剩余3条评论

5
这里是一种基于NumPy的方法——
# Get unique header strings for input dataframes
unq1,ID1 = np.unique(df['Event'],return_inverse=True)
unq2,ID2 = np.unique(df['Status'],return_inverse=True)

# Get linear indices/tags corresponding to grouped headers
tag = ID1*(ID2.max()+1) + ID2

# Setup 2D Numpy array equivalent of expected Dataframe
out = np.zeros((len(unq1),len(unq2)),dtype=int)
unqID, count = np.unique(tag,return_counts=True)
np.put(out,unqID,count)

# Finally convert to Dataframe
df_out = pd.DataFrame(out,columns=unq2)
df_out.index = unq1

以下是更一般情况下的示例输入和输出 -

In [179]: df
Out[179]: 
  Event   Status
0   Sit     PASS
1   Run  SUCCESS
2  Walk  SUCCESS
3   Run     PASS
4   Run  SUCCESS
5  Walk   FAILED
6  Walk     PASS

In [180]: df_out
Out[180]: 
      FAILED  PASS  SUCCESS
Run        0     1        2
Sit        0     1        0
Walk       1     1        1

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