【问题标题】:Count total number of occurrences in pandas dataframe with a condition使用条件计算熊猫数据框中出现的总次数
【发布时间】:2018-04-17 12:58:34
【问题描述】:

我有这个数据框:

cat_df.head()

   category depth
0   food    0.0
1   food    1.0
2   sport   1.0
3   food    3.0
4   school  0.0
5   school  0.0
6   school  1.0
...

depth = 0 代表根发布,depth > 0 是 cmets。

对于每个类别,我想计算根发布的数量 (depth=0) 和 cmets 的数量 (depth>0)。

我使用value_counts() 来计算唯一值:

cat_df['category'].value_counts().head(15)

category     total number 
food         44062
sport        38004
school       11080
life         8810
...

我以为我可以将['depth'] == 0 作为数据框内的条件,但它不起作用:

cat_df[cat_df['depth'] == 0].value_counts().head(5)

如何获得 depth=0 和 depth>0 的总出现次数?

我想把它放在这样的表格中:

category | total number | depth=0 | depth>0 
...

【问题讨论】:

    标签: python pandas dataframe pandas-groupby


    【解决方案1】:

    您只能使用一个groupby 来提高性能:

    df = (cat_df['depth'].ne(0)
                         .groupby(cat_df['category'])
                         .value_counts()
                         .unstack(fill_value=0)
                         .rename(columns={0:'depth=0', 1:'depth>0'})
                         .assign(total=lambda x: x.sum(axis=1))
                         .reindex(columns=['total','depth=0','depth>0']))
    
    print (df)
    depth     total  depth=0  depth>0
    category                         
    food          3        1        2
    school        3        2        1
    sport         1        0        1
    

    解释

    1. 首先比较 depth 列不等于 Series.ne (!=)
    2. groupby 按列 categorySeriesGroupBy.value_counts
    3. unstack重塑
    4. Rename 字典列
    5. assign 创建新的total
    6. 对于列的自定义顺序添加reindex

    编辑:

    cat_df = pd.DataFrame({'category': ['food', 'food', 'sport', 'food', 'school', 'school', 'school'], 'depth': [0.0, 1.0, 1.0, 3.0, 0.0, 0.0, 1.0], 'num_of_likes': [10, 10, 10, 20, 20, 20, 20]})
    

    print (cat_df)
      category  depth  num_of_likes
    0     food    0.0            10
    1     food    1.0            10
    2    sport    1.0            10
    3     food    3.0            20
    4   school    0.0            20
    5   school    0.0            20
    6   school    1.0            20
    
    df = (cat_df['depth'].ne(0)
                         .groupby([cat_df['num_of_likes'], cat_df['category']])
                         .value_counts()
                         .unstack(fill_value=0)
                         .rename(columns={0:'depth=0', 1:'depth>0'})
                         .assign(total=lambda x: x.sum(axis=1))
                         .reindex(columns=['total','depth=0','depth>0'])
                         .reset_index()
                         .rename_axis(None, axis=1)
    )
    
    print (df)
       num_of_likes category  total  depth=0  depth>0
    0            10     food      2        1        1
    1            10    sport      1        0        1
    2            20     food      1        0        1
    3            20   school      3        2        1
    

    编辑1:

    s = cat_df.groupby('category')['num_of_likes'].sum()
    print (s)
    category
    food      40
    school    60
    sport     10
    Name: num_of_likes, dtype: int64
    
    df = (cat_df['depth'].ne(0)
                         .groupby(cat_df['category'])
                         .value_counts()
                         .unstack(fill_value=0)
                         .rename(columns={0:'depth=0', 1:'depth>0'})
                         .assign(total=lambda x: x.sum(axis=1))
                         .reindex(columns=['total','depth=0','depth>0'])
                         .reset_index()
                         .rename_axis(None, axis=1)
                         .assign(num_of_likes=lambda x: x['category'].map(s))
    )
    print (df)
      category  total  depth=0  depth>0  num_of_likes
    0     food      3        1        2            40
    1   school      3        2        1            60
    2    sport      1        0        1            10
    

    【讨论】:

      【解决方案2】:

      这是使用pandas.concat的一种方式:

      total = df.groupby('category').size()
      zero = df[df.depth == 0].groupby('category').size()
      nonzero = df[df.depth > 0].groupby('category').size()
      
      res = pd.concat([total, zero, nonzero], axis=1)\
              .rename(columns={0: 'total', 1: 'zero', 2: 'nonzero'})\
              .fillna(0).astype(int)
      
      print(res)
      
      #         total  zero   nonzero
      # food        3     1         2
      # school      3     2         1
      # sport       1     0         1
      

      【讨论】:

      • 谢谢。看起来列的顺序有误导性或名称混淆
      【解决方案3】:

      我会做什么crosstab

      pd.crosstab(df.category,df.depth.ne(0),margins=True).iloc[:-1,:]
      Out[618]: 
      depth     False  True  All
      category                  
      food          1     2    3
      school        2     1    3
      sport         0     1    1
      

      如果需要名字加重命名

      pd.crosstab(df.category,df.depth.ne(0),margins=True).iloc[:-1,:].rename(columns={True:'depth>0',False:'depth=0'})
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-13
        • 1970-01-01
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        • 2023-02-20
        相关资源
        最近更新 更多