相关文章推荐
烦恼的上铺  ·  pandas 函式 API - Azure ...·  2 天前    · 
独立的日记本  ·  pandas ...·  5 天前    · 
开朗的键盘  ·  Pandas中isin函数 ...·  1 周前    · 
讲道义的硬盘  ·  Pandas之数据清洗 - ...·  1 周前    · 
帅气的领带  ·  HTML5中的拖放 - relucent ...·  6 月前    · 
腹黑的火柴  ·  了解Spring ...·  1 年前    · 
飘逸的野马  ·  Stable ...·  1 年前    · 

Pandas groupby mean()没有忽略NaNs

12 人关注

如果我计算一个groupby对象的平均值,并且在其中一个组内有一个NaN(s),那么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()
1  1.5
2  3.0
c.groupby('b').agg(np.mean)
1  1.5
2  3.0

我想收到以下结果。

1 1.5 2 NaN

我知道我可以事先替换NaN,而且我也许可以自己写一个聚合函数,只要NaN在组内,就返回NaN。不过这个函数不会被优化。

你知道有什么参数可以用优化后的函数实现所需的行为吗?

Btw,我认为所需的行为在pandas的前一个版本中已经实现。

1 个评论
Pandas的这种行为是可怕的......所提出的解决方案中,没有一个能让 np.mean() 这样的标准函数正常工作(返回NaN)。
python
pandas
dataframe
nan
Tim Tee
Tim Tee
发布于 2019-01-09
6 个回答
Mayank Porwal
Mayank Porwal
发布于 2020-12-11
已采纳
0 人赞同

默认情况下, pandas 会跳过 Nan 的值。你可以通过指定 skipna=False 使其包括 Nan

In [215]: c.groupby('b').agg({'a': lambda x: x.mean(skipna=False)})
Out[215]: 
1  1.5
2  NaN
    
Dmitriy Work
Dmitriy Work
发布于 2020-12-11
0 人赞同

There is mean(skipna=False) , but it's not working

GroupBy聚合方法(最小、最大、平均、中位数等)有 skipna 参数,就是为了这个确切的任务,但目前(5月-2020年)似乎有一个 bug (issue opened on mar-2020), which prevents it from working correctly.

Quick workaround

在此评论的基础上完成工作实例。 @Serge Ballesta , @RoelAdriaans

>>> 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)
1  1.5
2  NaN

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

Mortz
Mortz
发布于 2020-12-11
0 人赞同

Use the skipna option -

c.groupby('b').apply(lambda g: g.mean(skipna=False))
    
Serge Ballesta
Serge Ballesta
发布于 2020-12-11
0 人赞同

另一种方法是使用一个 价值 的,默认情况下不会被忽略,例如: np.inf

>>> c = pd.DataFrame({'a':[1,np.inf,2,3],'b':[1,2,1,2]})
>>> c.groupby('b').mean()
1  1.500000
2       inf
    
在计算平均值之前,你可以使用 fillna(np.inf) ,在平均值之后,你可以使用 .replace([np.inf, -np.inf], np.nan) 来恢复纳米值。
KEXIN WANG
KEXIN WANG
发布于 2020-12-11
0 人赞同

它有三种不同的方法。

  • slowest :
  •     c.groupby('b').apply(lambda g: g.mean(skipna=False))
    
  • faster than apply but slower than default sum:
  •     c.groupby('b').agg({'a': lambda x: x.mean(skipna=False)})
    
  • Fastest but need more codes:
  •     method3 = c.groupby('b').sum()
        nan_index = c[c['b'].isna()].index.to_list()
        method3.loc[method3.index.isin(nan_index)] = np.nan
        
    Pierre D
    Pierre D
    发布于 2020-12-11
    0 人赞同

    我来到这里是为了寻找一种快速(矢量)的方法,但没有找到。另外,在复数的情况下, groupby 的表现有点奇怪:它不喜欢 mean() ,而对于 sum() ,它将把所有数值都是 NaN 的组转换成 0+0j

    因此,这是我想出的办法。

    Setup :

    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
    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
    1  3.0  3.0 NaN
    2  NaN  NaN NaN
    

    只有在组内所有数值都是NaN的情况下,才会NaN:

    cnt = gb.count()
    gb.sum() * (cnt / cnt)
    Out[]:
         b    c                   d
    1  3.0  3.0  0.000000+2.000000j
    2  3.0  NaN                 NaN
    

    推论:复数的平均值:

    cnt = gb.count()
    gb.sum() / cnt
    Out[]: