【问题标题】:What is the pythonic way of collapsing values into a set for multiple columns per each group in pandas dataframes?在pandas数据帧中,为每组每组的多列将值折叠成一组的pythonic方法是什么?
【发布时间】:2018-03-28 22:11:07
【问题描述】:

给定一个数据框,将列的每组的值折叠成一个集合很简单:

df.groupby('A')['B'].apply(set)

但是,如果您想在多列上执行此操作并且结果要在数据框中,您如何以 Python 方式执行此操作?

例如对于以下数据框:

import pandas as pd
df = pd.DataFrame({'user_id': [1, 2, 3, 4, 1, 2, 3], 
               'class_type': ['Krav Maga', 'Yoga', 'Ju-jitsu', 'Krav Maga', 'Ju-jitsu','Krav Maga', 'Karate'], 
               'instructor': ['Bob', 'Alice','Bob', 'Alice','Alice', 'Alice','Bob']})

想要的结果是下面以pythonic方式生成的数据框:

|user_id|class_type             |instructor     |
|-------|-----------------------|---------------|
|  1    | {Krav Maga, Ju-jitsu} | {Bob, Alice}  |
|  2    | {Krav Maga, Yoga}     | {Alice}       | 
|  3    | {Karate, Ju-jitsu}    | {Bob}         | 
|  4    | {Krav Maga}           | {Alice}       | 

这是一个虚拟示例。这个问题源于:“如果我有一个包含 30 列的表,我想以 Python 的方式实现这一点怎么办?”

目前我有一个解决方案,但我认为这不是最好的方法:

df[['grouped_B', 'grouped_C']] = df.groupby('A')[['B','C']].transform(set)
deduped_and_collapsed_df = df.groupby('A')[['A','grouped_B', 'grouped_C']].head(1)

提前谢谢你!

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:
    In [11]: df.groupby('user_id', as_index=False).agg(lambda col: set(col.values.tolist()))
    Out[11]:
       user_id             class_type    instructor
    0        1  {Krav Maga, Ju-jitsu}  {Alice, Bob}
    1        2      {Yoga, Krav Maga}       {Alice}
    2        3     {Ju-jitsu, Karate}         {Bob}
    3        4            {Krav Maga}       {Alice}
    

    来自@jezrael 的或更短的版本:

    In [12]: df.groupby('user_id').agg(lambda x: set(x))
    Out[12]:
                        class_type    instructor
    user_id
    1        {Krav Maga, Ju-jitsu}  {Alice, Bob}
    2            {Yoga, Krav Maga}       {Alice}
    3           {Ju-jitsu, Karate}         {Bob}
    4                  {Krav Maga}       {Alice}
    

    【讨论】:

    【解决方案2】:

    这是一个collections.defaultdict 方法。 Pythonic 是主观的。

    这个解决方案肯定不是 Pandonic / Pandorable。将groupby.agglambda 一起使用时,数据帧通常会产生较大的开销,因此您可能会发现以下解决方案更有效。

    from collections import defaultdict
    
    d_class, d_instr = defaultdict(set), defaultdict(set)
    
    for row in df.itertuples():
        idx, class_type, instructor, user_id = row
        d_class[user_id].add(class_type)
        d_instr[user_id].add(instructor)
    
    res = pd.DataFrame([d_class, d_instr]).T.rename(columns={0: 'class_type', 1: 'instructor'})
    

    结果:

                  class_type    instructor
    1  {Krav Maga, Ju-jitsu}  {Bob, Alice}
    2      {Krav Maga, Yoga}       {Alice}
    3     {Ju-jitsu, Karate}         {Bob}
    4            {Krav Maga}       {Alice}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-19
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 2020-10-09
      • 2022-08-18
      相关资源
      最近更新 更多