【问题标题】:Count occurrences of list item in dataframe column, grouped by another column计算数据框列中列表项的出现次数,按另一列分组
【发布时间】:2021-11-09 04:25:08
【问题描述】:

我有一个数据框,其中一列包含非唯一的单词列表,另一列包含从 1 到 3 的数字。我想计算数据框中每个单词的出现次数,按第二列中的数字分组.

例子:

words category
cat, dog, dog 1
cat, cat, mouse 1
mouse, cat, dog, elephant 2
elephant, elephant 3

想要的结果:

word 1 2 3
cat 3 1 0
dog 2 1 0
mouse 1 1 0
elephant 0 1 2

我找到了一些与我正在尝试做的事情相近的答案,比如this one 和其他一些使用 value_counts 的答案,但没有一个完全适合这个。帮忙?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    我们可以使用DataFrame.explode + crosstab:

    # If Not Already a List
    # df['words'] = df['words'].str.split(', ')
    
    new_df = df.explode('words')
    new_df = pd.crosstab(
        new_df['words'], new_df['category']
    ).reset_index().rename_axis(columns=None)
    

    或者在explode之后加上groupby size + unstack

    new_df = (
        df.explode('words')  # Explode List into Rows
            .groupby(['words', 'category']).size()  # Calculate Group Sizes
            .unstack(fill_value=0)  # Convert Category values to column names 
            .reset_index().rename_axis(columns=None)  # Cleanup
    )
    

    DataFrame.value_counts + unstackexplode 之后:

    new_df = (
        df.explode('words')  # Explode List into Rows
            .value_counts()  # Count Value Pairs
            .unstack(level='category',  # Convert Category values to column names
                     fill_value=0)
            .reset_index().rename_axis(columns=None)  # Cleanup
    )
    

    new_df:

          words  1  2  3
    0       cat  3  1  0
    1       dog  2  1  0
    2  elephant  0  1  2
    3     mouse  1  1  0
    

    设置:

    import pandas as pd
    
    df = pd.DataFrame({
        'words': [['cat', 'dog', 'dog'], ['cat', 'cat', 'mouse'],
                  ['mouse', 'cat', 'dog', 'elephant'], ['elephant', 'elephant']],
        'category': [1, 1, 2, 3]
    })
    

    【讨论】:

      【解决方案2】:

      我觉得对于这样的数据结构,如果数据在 Pandas 之外被处理,然后返回到 Pandas 中,你可能会有更好的性能(当然,这只有在你关心性能的情况下才重要,不需要进行不必要的优化) -当然,测试是确保这是正确的唯一方法:

      from collections import defaultdict
      d = defaultdict(int)
      for words, number in zip(df.words, df.category):
          for word in words:
              d[(word, number)] += 1
      
      
      d
      
      defaultdict(int,
                  {('cat', 1): 3,
                   ('dog', 1): 2,
                   ('mouse', 1): 1,
                   ('mouse', 2): 1,
                   ('cat', 2): 1,
                   ('dog', 2): 1,
                   ('elephant', 2): 1,
                   ('elephant', 3): 2})
      

      构建数据框:

       (pd.DataFrame(d.values(), index = d)
          .unstack(fill_value = 0)
          .droplevel(0, axis = 1)
        )
      
                1  2  3
      cat       3  1  0
      dog       2  1  0
      elephant  0  1  2
      mouse     1  1  0
      

      借鉴@HenryEcker,您还可以使用Counter 函数:

       from itertools import product, chain
       from collections import Counter
      # integers are put into a list as `product` works on iterables
      pairing = (product(left, [right]) 
                 for left, right 
                 in zip(df.words, df.category))
       outcome = Counter(chain.from_iterable(pairing))
       outcome
      Counter({('cat', 1): 3,
               ('dog', 1): 2,
               ('mouse', 1): 1,
               ('mouse', 2): 1,
               ('cat', 2): 1,
               ('dog', 2): 1,
               ('elephant', 2): 1,
               ('elephant', 3): 2})
      

      像以前一样构建数据框:

       (pd.DataFrame(outcome.values(), index = outcome)
          .unstack(fill_value = 0)
          .droplevel(0, axis = 1)
        )
      
                1  2  3
      cat       3  1  0
      dog       2  1  0
      elephant  0  1  2
      mouse     1  1  0
      

      【讨论】:

      • 似乎collections.Counter 可能比defaultdict 更惯用。 Counter([(word, number) for words, number in zip(df.words, df.category) for word in words])
      • Counter 更加地道,但是,它做了很多其他的事情,使其比使用 defaultdict 实例化 int 慢
      • 我很确定自从在 python 3 中将 Counter 操作移至 C 以来,情况并非如此。无论如何,我当前的测试使它们在这个示例中几乎完全相同(Counter 是0.07µs 更快)
      猜你喜欢
      • 2022-01-04
      • 2021-04-12
      • 2022-06-16
      • 1970-01-01
      • 2021-10-15
      • 2021-08-11
      • 2019-07-23
      • 2021-09-09
      • 2018-11-14
      相关资源
      最近更新 更多