【问题标题】:Weighted average of multiple columns using groupby, dropping NaNs column-wise使用 groupby 对多列进行加权平均,逐列删除 NaN
【发布时间】:2020-03-26 13:55:22
【问题描述】:

我有这样的情况 Pandas Group Weighted Average of Multiple Columns 但其中一列的某些值有时是 NaN。

也就是说,我正在做以下事情:

import pandas as pd
import numpy as np

df=pd.DataFrame({'category':['a','a','b','b'],
 'var1':np.random.randint(0,100,4),
 'var2':np.random.randint(0,100,4),
 'weights':np.random.randint(0,10,4)})
df.loc[1,'var1']=np.nan
df


      category  var1  var2  weights
0        a      74.0    99        9
1        a       NaN     8        4
2        b      13.0    86        2
3        b      49.0    38        7

def weighted(x, cols, w="weights"):
    # Following fails when NaNs might be present:
    #return pd.Series(np.average(x[cols], weights=x[w], axis=0), cols)
    return pd.Series([np.nan if x.dropna(subset=[c]).empty else np.average(x.dropna(subset=[c])[c], weights =x.dropna(subset=[c])[w] ) for c in cols], cols)

df.groupby('category').apply(weighted, ['var1', 'var2'])


          var1       var2
category                 
a         74.0  57.846154
b         23.0   8.000000

我想要一个更好的方法来做到这一点,但 np.nanmean 不允许权重。 np.average 不允许控制 NaN 处理的选项。

【问题讨论】:

  • 你能先去掉 NaN 值吗?
  • @user1558604:我不能删除一行,因为我想要var2 意味着即使var1 不存在。
  • 你找到解决办法了吗?
  • @LuisBlanche 我的问题中的代码似乎比其他任何代码都干净,所以这仍然是我的解决方案。我只是要求一种更清洁/更体面的方式来做到这一点。

标签: python pandas numpy pandas-groupby


【解决方案1】:

没有比我的建议更清晰的答案,我建议使用下面的功能还不错:

import pandas as pd
import numpy as np

def weighted_means_by_column_ignoring_NaNs(x, cols, w="weights"):
    """ This takes a DataFrame and averages each data column (cols),
        weighting observations by column w, but ignoring individual NaN
        observations within each column.
    """
    return pd.Series([np.nan if x.dropna(subset=[c]).empty else \
                      np.average(x.dropna(subset=[c])[c], 
                      weights =x.dropna(subset=[c])[w] )  \
                      for c in cols], cols)

示例用法如下

df=pd.DataFrame({'category':['a','a','b','b'],
 'var1':np.random.randint(0,100,4),
 'var2':np.random.randint(0,100,4),
 'weights':np.random.randint(0,10,4)})
df.loc[1,'var1']=np.nan
df


      category  var1  var2  weights
0        a      74.0    99        9
1        a       NaN     8        4
2        b      13.0    86        2
3        b      49.0    38        7

df.groupby('category').apply(weighted_means_by_column_ignoring_NaNs), 
        ['var1', 'var2'])


          var1       var2
category                 
a         74.0  57.846154
b         23.0   8.000000

【讨论】:

    【解决方案2】:

    如何将 Nan 值设置为零并创建一个新列 var * weight。然后你可以使用groupby 得到结果。

    【讨论】:

      【解决方案3】:

      您可以在调用apply 和调用unstack 之前使用meltdropna 预处理您的数据帧

      wa=lambda x: np.average(x.value, weights=x.weights)
      df_avg = (df.melt(['category', 'weights']).dropna().groupby(['category', 'variable'])
                                                         .apply(wa).unstack())
      
      Out[40]:
      variable  var1       var2
      category
      a         74.0  71.000000
      b         41.0  48.666667
      

      注意:您想要的输出与示例不匹配。 (a, 'var2')的值为(99 * 9 + 8 * 4) / (9 + 4) = 71

      【讨论】:

        猜你喜欢
        • 2021-01-10
        • 2023-02-22
        • 2021-09-03
        • 2019-01-28
        • 1970-01-01
        • 1970-01-01
        • 2015-06-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多