【问题标题】:Pandas count NAs with a groupby for all columns [duplicate]Pandas 对所有列使用 groupby 计数 NA [重复]
【发布时间】:2020-01-19 14:22:38
【问题描述】:

This question 展示了如何计算数据框中特定列 C 的 NA。如何计算所有列(不是 groupby 列)的 NA?

这是一些不起作用的测试代码:

#!/usr/bin/env python3

import pandas as pd
import numpy as np

df = pd.DataFrame({'a':[1,1,2,2], 
                   'b':[1,np.nan,2,np.nan],
                   'c':[1,np.nan,2,3]})

# result = df.groupby('a').isna().sum()
# AttributeError: Cannot access callable attribute 'isna' of 'DataFrameGroupBy' objects, try using the 'apply' method

# result = df.groupby('a').transform('isna').sum()
# AttributeError: Cannot access callable attribute 'isna' of 'DataFrameGroupBy' objects, try using the 'apply' method

result = df.isna().groupby('a').sum()
print(result)
# result:
#          b    c
# a
# False  2.0  1.0

result = df.groupby('a').apply(lambda _df: df.isna().sum())
print(result)
# result:
#    a  b  c
# a
# 1  0  2  1
# 2  0  2  1

期望的输出:

     b    c
a
1    1    1
2    1    0

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    最好避免 groupby.apply 支持 cythonized 的基本功能,因为这可以更好地适应许多组。这将导致性能大幅提升。在这种情况下,首先检查整个DataFrame 上的isnull(),然后检查groupby + sum

    df[df.columns.difference(['a'])].isnull().groupby(df.a).sum().astype(int)
    #   b  c
    #a      
    #1  1  1
    #2  1  0
    

    为了说明性能提升:

    import pandas as pd
    import numpy as np
    
    N = 50000
    df = pd.DataFrame({'a': [*range(N//2)]*2,
                       'b': np.random.choice([1, np.nan], N),
                       'c': np.random.choice([1, np.nan], N)})
    
    %timeit df[df.columns.difference(['a'])].isnull().groupby(df.a).sum().astype(int)
    #7.89 ms ± 187 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit df.groupby('a')[['b', 'c']].apply(lambda x: x.isna().sum())
    #9.47 s ± 111 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    【讨论】:

      【解决方案2】:

      您的问题有答案(您将_df 错误输入为df):

      result = df.groupby('a')['b', 'c'].apply(lambda _df: _df.isna().sum())
      result
         b  c
      a      
      1  1  1
      2  1  0
      

      【讨论】:

        【解决方案3】:

        applyisnasum 一起使用。另外,我们选择了正确的列,所以我们不会得到不必要的a 列:

        注意apply 可能会很慢,建议使用其中一种矢量化解决方案,请参阅WenYoBenAnkyALollz 的答案

        df.groupby('a')[['b', 'c']].apply(lambda x: x.isna().sum())
        

        输出

           b  c
        a      
        1  1  1
        2  1  0
        

        【讨论】:

          【解决方案4】:

          另一种方法是在a 上使用set_index(),在索引和总和上使用 groupby:

          df.set_index('a').isna().groupby(level=0).sum()*1
          

          或者:

          df.set_index('a').isna().groupby(level=0).sum().astype(int)
          

          或者没有 groupby 礼貌@WenYoBen:

          df.set_index('a').isna().sum(level=0).astype(int)
          

             b  c
          a      
          1  1  1
          2  1  0
          

          【讨论】:

          • df.set_index('a').isna().sum(level=0).astype(int)
          【解决方案5】:

          我会先做count 然后sub 用value_counts,我没有用apply 的原因,因为它通常性能很差

          df.groupby('a')[['b','c']].count().rsub(df.a.value_counts(dropna=False),axis=0)
          Out[78]: 
             b  c
          1  1  1
          2  1  0
          

          另类

          df.isna().drop('a',1).astype(int).groupby(df['a']).sum()
          Out[83]: 
             b  c
          a      
          1  1  1
          2  1  0
          

          【讨论】:

            【解决方案6】:

            使用apply后需要drop栏目。

            df.groupby('a').apply(lambda x: x.isna().sum()).drop('a',1)
            

            输出:

                b   c
            a       
            1   1   1
            2   1   0
            

            【讨论】:

              【解决方案7】:

              又一个肮脏的工作:

              df.set_index('a').isna().astype(int).groupby(level=0).sum()
              

              输出:

                  b   c
              a       
              1   1   1
              2   1   0
              

              【讨论】:

                【解决方案8】:

                您可以编写自己的聚合函数,如下所示:

                df.groupby('a').agg(lambda x: x.isna().sum())
                

                导致

                     b    c
                a          
                1  1.0  1.0
                2  1.0  0.0
                

                【讨论】:

                  猜你喜欢
                  • 2020-06-10
                  • 2021-01-24
                  • 1970-01-01
                  • 2019-08-03
                  • 2015-10-30
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-08-26
                  • 2018-09-06
                  相关资源
                  最近更新 更多