【问题标题】:Use groupby in Pandas to count things in one column in comparison to another在 Pandas 中使用 groupby 来计算一列中与另一列相比的内容
【发布时间】:2023-01-19 21:37:38
【问题描述】:

也许 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'])

【问题讨论】:

  • 请关注@piRSquared 的解决方案,与其他解决方案相比,它看起来非常整洁且速度更快

标签: python pandas dataframe


【解决方案1】:

尝试这个:

 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

【讨论】:

  • 这是一个有趣的比较! :)
  • Python 之禅,第 3 号。简单胜于复杂。
【解决方案2】:

我会做:

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

或者使用 fill_value 参数:

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


定时

【讨论】:

  • 是的,你的解决方案更快
【解决方案3】:

另一种解决方案,使用 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 DF 的计时:

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)
)

【讨论】:

  • 你能用sum而不是len来测试pivot_table吗?我认为 len 正在减慢速度。 df.assign(ones = np.ones(len(df))).pivot_table(index='Event', columns='Status', aggfunc=np.sum, values = 'ones')
  • @ayhan,这很有趣 - 我认为 groupby()...value_counts() 解决方案应该更快......
  • 实际上,我对交叉表感到惊讶。我希望它是最快的,因为它正是为此而设计的。不过它的规模很好。
  • @ayhan,刚刚检查了 pandas 的 crosstab() 实现 - 它在内部使用 pivot_table(..., aggfunc=len)pivot_table(..., aggfunc=aggfunc)(如果指定了 aggfunc);)
  • 顺便说一句,df.pivot_table(index='Event', columns='Status', aggfunc='count', fill_value=0) 快得多(可能是因为它不需要新列):)
【解决方案4】:

这是一个基于 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

【讨论】:

    猜你喜欢
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 2021-09-13
    • 1970-01-01
    • 2019-01-03
    • 2019-10-07
    • 2020-07-02
    • 1970-01-01
    相关资源
    最近更新 更多