熊猫groupby mean()不忽略NaN

时间:2019-01-09 08:42:57

标签: python pandas dataframe nan

如果我计算一个groupby对象的平均值,并且在一个组中有一个NaN,则NaN将被忽略。即使使用np.mean,它仍然仅返回所有有效数字的平均值。我希望一旦有一个NaN进入小组,就会返回NaN的行为。这是行为的简化示例

import pandas as pd
import numpy as np
c = pd.DataFrame({'a':[1,np.nan,2,3],'b':[1,2,1,2]})
c.groupby('b').mean()
     a
b     
1  1.5
2  3.0
c.groupby('b').agg(np.mean)
     a
b     
1  1.5
2  3.0

我想收到以下结果:

     a
b     
1  1.5
2  NaN

我知道我可以预先替换NaN,并且我可能可以编写自己的聚合函数以在NaN进入该组后立即返回NaN。不过,此功能不会进行优化。

您知道使用优化功能实现所需行为的参数吗?

顺便说一句,我认为期望的行为是在以前版本的熊猫中实现的。

6 个答案:

答案 0 :(得分:4)

mean(skipna=False),但不起作用

GroupBy聚合方法(最小值,最大值,均值,中位数等)具有skipna参数,该参数适用于此确切任务,但目前(2020年5月)似乎有一个{{ 3}}(发行日期为2020年3月),这使其无法正常工作。

快速解决方法

基于以下注释的完整工作示例:bug@Serge Ballesta

>>> import pandas as pd
>>> import numpy as np
>>> c = pd.DataFrame({'a':[1,np.nan,2,3],'b':[1,2,1,2]})
>>> c.fillna(np.inf).groupby('b').mean().replace(np.inf, np.nan)

     a
b     
1  1.5
2  NaN

有关其他信息和更新,请点击上面的链接。

答案 1 :(得分:3)

默认情况下,pandas跳过Nan值。您可以通过指定Nan使其包含skipna=False

In [215]: c.groupby('b').agg({'a': lambda x: x.mean(skipna=False)})
Out[215]: 
     a
b     
1  1.5
2  NaN

答案 2 :(得分:1)

使用skipna选项-

c.groupby('b').apply(lambda g: g.mean(skipna=False))

答案 3 :(得分:1)

另一种方法是使用默认不忽略的 value ,例如np.inf

>>> c = pd.DataFrame({'a':[1,np.inf,2,3],'b':[1,2,1,2]})
>>> c.groupby('b').mean()
          a
b          
1  1.500000
2       inf

答案 4 :(得分:0)

有三种不同的方法:

  1. 最慢​​
    c.groupby('b').apply(lambda g: g.mean(skipna=False))
  1. 比应用速度快,但比默认金额慢
    c.groupby('b').agg({'a': lambda x: x.mean(skipna=False)})
  1. 最快,但需要更多代码
    method3 = c.groupby('b').sum()
    nan_index = c[c['b'].isna()].index.to_list()
    method3.loc[method3.index.isin(nan_index)] = np.nan

enter image description here

答案 5 :(得分:0)

我登陆这里是为了寻找一种快速(矢量化)的方法,但是没有找到。另外,在复数的情况下,groupby的行为有点奇怪:它不像mean(),并且使用sum()它将转换所有值为NaN的组进入0+0j

所以,这是我想出的:

设置

df = pd.DataFrame({
    'a': [1, 2, 1, 2],
    'b': [1, np.nan, 2, 3],
    'c': [1, np.nan, 2, np.nan],
    'd': np.array([np.nan, np.nan, 2, np.nan]) * 1j,
})
gb = df.groupby('a')

默认行为

gb.sum()

Out[]:
     b    c                   d
a                              
1  3.0  3.0  0.000000+2.000000j
2  3.0  0.0  0.000000+0.000000j

一个NaN会杀死该小组

cnt = gb.count()
siz = gb.size()
mask = siz.values[:, None] == cnt.values
gb.sum().where(mask)

Out[]:
     b    c   d
a              
1  3.0  3.0 NaN
2  NaN  NaN NaN

如果组中的所有值均为NaN ,则仅NaN

cnt = gb.count()
gb.sum() * (cnt / cnt)
out

Out[]:
     b    c                   d
a                              
1  3.0  3.0  0.000000+2.000000j
2  3.0  NaN                 NaN

推论:复数的平均值

cnt = gb.count()
gb.sum() / cnt

Out[]:
     b    c                   d
a                              
1  1.5  1.5  0.000000+2.000000j
2  3.0  NaN                 NaN