【问题标题】:Panda groupby: counting rows satisfying condition on other columns?Panda groupby:计算满足其他列条件的行?
【发布时间】:2019-01-22 19:49:14
【问题描述】:

我想在 pandas 中做一个groupby,作为结果获得一个数据框,该数据框具有用于groupby 的列作为列,每个组的元素数量以及其中每个组中的元素数量,满足/不满足基于另一列值的条件的元素数。

例如是这样的输入:

type    success
A       True
B       False
A       False
C       True

我想要类似的东西:

type    total    numOfSuccess numOfFailure
A       2        1             1
B       1        0             1
C       1        1             0

在 pyspark 中我是这样做的

import pyspark.sql.functions as F
df = df.groupBy("type").agg(\
    F.count('*').alias('total'), \
    F.sum(F.when(F.col('success')=="true", 1).otherwise(0)).alias('numOfSuccess'),
    F.sum(F.when(F.col('success')!="true", 1).otherwise(0)).alias('numOfFails'))

在 pandas 中,我只能得到 totalnumOfSuccess 为:

df_new = df.groupby(['type'], as_index=False)['success'].agg({'total':'count', 'numOfSuccess':'sum'})

或者只有总数为:

df = df.groupby(['type']).size().reset_index(name='NumOfReqs')

但我无法获得第三列numOfFailures,而且如果有替代方法而不是对布尔值求和,那会更好,因为在我看来,in 可以扩展到其他情况也更容易。

我该怎么做?

【问题讨论】:

    标签: python pandas group-by pandas-groupby


    【解决方案1】:

    使用groupbyGroupBy.size 计算所有数据,然后计算每个需要旋转的类别 - 使用GroupBy.sizeunstackcrosstabpivot_table

    df1 = df.groupby('type').size().reset_index(name='count')
    df2 = (df.groupby(['type', 'success']).size().unstack(fill_value=0)
            .rename(columns={True:'numOfSuccess', False:'numOfFails'}))
    

    df2 的替代方案:

    df2 = pd.crosstab(df['type'], df['success'])
            .rename(columns={True:'numOfSuccess', False:'numOfFails'}))
    

    或者:

    df2 = (df.pivot_table(index='type', columns='success', fill_value=0, aggfunc='size')
            .rename(columns={True:'numOfSuccess', False:'numOfFails'}))
    

    df_new = df1.join(df2, on='type')
    print (df_new)
      type  count  numOfFails  numOfSuccess
    0    A      2           1             1
    1    B      1           1             0
    2    C      1           0             1
    

    另一种解决方案是在crosstab 中使用参数margins 并通过使用iloc 进行索引来删除最后一行:

    df = (pd.crosstab(df['type'], df['success'], margins=True)
            .rename(columns={True:'numOfSuccess', False:'numOfFails', 'All':'count'})
            .iloc[:-1]
            .reset_index()
            .rename_axis(None, axis=1))
    
    print (df)
      type  numOfFails  numOfSuccess  count
    0    A           1             1      2
    1    B           1             0      1
    2    C           0             1      1
    

    编辑:如果可能 TrueFalse 不存在,请添加 reindex 以添加缺少的列:

    print (df)
      type  success
    0    A     True
    1    B     True
    2    A     True
    3    C     True
    
    df1 = df.groupby('type').size().reset_index(name='count')
    df2 = (df.groupby(['type', 'success']).size().unstack(fill_value=0)
             .reindex(columns=[True, False], fill_value=0)
             .rename(columns={True:'numOfSuccess', False:'numOfFails'}))
    
    
    df_new = df1.join(df2, on='type')
    print (df_new)
      type  count  numOfSuccess  numOfFails
    0    A      2             2           0
    1    B      1             1           0
    2    C      1             1           0
    

    【讨论】:

    • 很好的解决方案。! +1
    • @MayankPorwal - 谢谢!
    • 您好,感谢您的解决方案...不过有一个小问题:如果成功列全部为真,numOfFails 列将不存在。有没有简单的解决方案?
    • @FrancescoBoi - 当然,等一下
    • 非常感谢。很好的答案,你一直非常乐于助人和善良。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-21
    • 1970-01-01
    • 2023-03-22
    • 2023-01-25
    • 1970-01-01
    相关资源
    最近更新 更多