按加权平均值分组,允许零值权重

Group by weighted mean, allowing for zero value weights

我想在 group-by 语句中取列的加权平均值,就像这样

import pandas as pd
import numpy as np

df = pd.DataFrame({'group': ['A', 'A', 'A', 'B', 'B', 'B'],
                   'value': [0.4, 0.3, 0.2, 0.4, 0.3, 0.2],
                   'weight': [2, 2, 4, 3, 1, 2]})

df_grouped = df.groupby('group')[['value', 'weight']].apply(lambda x: sum(x['value']*x['weight'])/sum(x['weight']))

df_grouped
Out[17]: 
group
A    0.275000
B    0.316667
dtype: float64

到目前为止一切都很好。 但是,在某些情况下权重总和为零,例如

df = pd.DataFrame({'group': ['A', 'A', 'A', 'B', 'B', 'B'],
                   'value': [0.4, 0.3, 0.2, 0.4, 0.3, 0.2],
                   'weight': [1, 2, 3, 0, 0, 0]})

在这种情况下,我想采用简单的方法。由于被零除,上面的表达式显然失败了。

我目前使用的方法是在权重和为1的地方将权重替换为1

df_temp = df.groupby('group')['weight'].transform('sum').reset_index()
df['new_weight'] = np.where(df_temp['weight']==0, 1, df['weight'])

df_grouped = df.groupby('group')[['value', 'new_weight']].apply(lambda x: sum(x['value']*x['new_weight'])/sum(x['new_weight']))

这是一个不错的解决方案。但这可以通过一行来实现吗?例如一些特殊功能?

如果您需要在一行中完成它,可以使用 lambda 中的三元运算符检查 Group By Sum 是否等于零,如下所示。如果总和分组为零,则使用常规平均值。

df.groupby('group')[['value', 'weight']].apply(lambda x:sum(x['value'])/len(x['weight'])  if (sum(x['weight'])) == 0 else sum(x['value']*x['weight'])/sum(x['weight']))

    group
    A    0.266667
    B    0.300000
    dtype: float64

上面片段的常规均值计算可以进一步缩小如下。

df.groupby('group')[['value', 'weight']].apply(lambda x:x['value'].mean() if (sum(x['weight'])) == 0 else sum(x['value']*x['weight'])/sum(x['weight']))

但是,我认为这种单行代码会降低代码的可读性。