Pandas分组多列加权平均

9

假设有以下数据框:

>>> 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
  category  var1  var2  weights
0        a    37    36        7
1        a    47    20        1
2        b    33     7        6
3        b    16     6        8

我可以按如下方式计算'var1'的加权平均值:

>>> Grouped=df.groupby('category')
>>> GetWeightAvg=lambda g: np.average(g['var1'], weights=g['weights'])
>>> Grouped.apply(GetWeightAvg)
category
a    38.250000
b    23.285714
dtype: float64

然而,我想知道是否有一种方法可以编写我的函数并将其应用于我的分组对象,以便在应用它时,可以指定要计算的列(或两列)。而不是在我的函数中写入'var1',我希望能够在应用函数时指定。

就像我可以这样获取两个列的未加权平均值:

>>> Grouped[['var1','var2']].mean()
          var1  var2
category            
a         42.0  28.0
b         24.5   6.5

我在想是否有一种并行的方法来使用加权平均值。

2个回答

14
你可以应用和返回两个平均值:
In [11]: g.apply(lambda x: pd.Series(np.average(x[["var1", "var2"]], weights=x["weights"], axis=0), ["var1", "var2"]))
Out[11]:
               var1       var2
category
a         38.250000  34.000000
b         23.285714   6.428571

你可以将这段代码稍微整理一下,写成一个函数:

In [21]: def weighted(x, cols, w="weights"):
             return pd.Series(np.average(x[cols], weights=x[w], axis=0), cols)

In [22]: g.apply(weighted, ["var1", "var2"])
Out[22]:
               var1       var2
category
a         38.250000  34.000000
b         23.285714   6.428571

这很有帮助。然而,我的某一列(而不是其他列)的一些值为NaN。对于那些值,我想通过删除NaN值并使用其他值来计算平均值。但是这个解决方案却返回NaN值。这个https://stackoverflow.com/questions/43049014/python-take-weighted-average-inside-pandas-groupby-while-ignoring-nan没有处理多列。np.nanmean不允许权重。np.average不允许控制NaN的处理选项。 - CPBL

0

继续Andy的解决方案,我想使用多级索引中的一个索引级别作为权重。

np.random.seed(1)
arrays = [list('AAABBB'), [0.01,0.02,0.03,0.07,0.09,0.11]]
tups = list(zip(*arrays))
x = pd.MultiIndex.from_tuples(tups)
df = pd.DataFrame(index=x,data= np.random.randint(10,100,(6,6)),columns = list('STUVWX'))
df.index.names = ['bin','prob']

             S   T   U   V   W   X
bin prob                          
A   0.0100  47  22  82  19  85  15
    0.0200  89  74  26  11  86  81
    0.0300  16  35  60  30  28  94
B   0.0700  21  38  39  24  60  78
    0.0900  97  97  96  23  19  17
    0.1100  73  71  32  67  11  10

将函数调整为使用其中一个索引级别作为权重。

def weighted(x, w="weights"):
    return pd.Series(np.average(x, weights=x.index.get_level_values(w), axis=0),index= x.columns)

并调用

df.groupby(level=['bin']).apply(weighted,  "prob")

这将会给出:

          S       T       U       V       W       X
bin                                                
A   45.5000 45.8333 52.3333 21.8333 56.8333 76.5000
B   67.5185 71.1111 55.1481 41.1852 26.3704 29.9630

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接