使用groupby agg()函数计算Python Pandas加权平均数

4

我希望能够在pandas的groupby agg()中使用自定义函数。我知道可以使用apply选项,但我想要做几次聚合。以下是我尝试实现加权平均的测试代码。

Python 代码

import pandas as pd
import numpy as np

def weighted_avg(df, values, weights):
    '''To calculate a weighted average in Pandas. Demo see https://www.statology.org/pandas-weighted-average/
    Example: df.groupby('Group Names').apply(w_avg, 'Results', 'AFY')'''
    v = df[values]
    w = df[weights]
    return (v * w).sum() / w.sum()

# below creates a dataframe.
dfr = pd.DataFrame(np.random.randint(1,50,size=(4,4)), columns=list('ABCD'))
dfr['group'] = [1, 1, 0, 1]

print(dfr)
dfr = dfr.groupby('group').agg({'A':'mean', 'B':'sum',
                    'C': lambda x: weighted_avg(dfr, 'D', 'C')}).reset_index()
print(dfr)

结果 - 输出

    A   B   C   D  group
0   5   2  17  38      1
1  35  30  22  32      1
2  15  18  16  11      0
3  46   6  20  34      1
    group     A      B       C
0      0  15.000000  18  29.413333
1      1  28.666667  38  29.413333
问题:加权平均值返回整个表的值,而不是“group”列的值。如何实现按组计算加权平均值的功能?

我尝试将groupby放在函数内部,像这里所示,但没有成功。

谢谢您的查阅。
3个回答

2
您可以在lambda中使用x(具体来说,使用它的.index)来获取所需的值。例如:
import pandas as pd
import numpy as np


def weighted_avg(group_df, whole_df, values, weights):
    v = whole_df.loc[group_df.index, values]
    w = whole_df.loc[group_df.index, weights]
    return (v * w).sum() / w.sum()


dfr = pd.DataFrame(np.random.randint(1, 50, size=(4, 4)), columns=list("ABCD"))
dfr["group"] = [1, 1, 0, 1]

print(dfr)
dfr = (
    dfr.groupby("group")
    .agg(
        {"A": "mean", "B": "sum", "C": lambda x: weighted_avg(x, dfr, "D", "C")}
    )
    .reset_index()
)
print(dfr)

输出:

    A   B   C   D  group
0  32   2  34  29      1
1  33  32  15  49      1
2   4  43  41  10      0
3  39  33   7  31      1

   group          A   B          C
0      0   4.000000  43  10.000000
1      1  34.666667  67  34.607143

编辑:正如@enke在评论中所述,您可以使用已过滤的数据帧调用weighted_avg函数:

weighted_avg(dfr.loc[x.index], 'D', 'C')

谢谢,我尝试了这个代码,但是出现了错误。 ...在第67行,df_g = df_g.groupby('item_name').agg(weighted_avg,'value', 'weight')... TypeError: weighted_avg()缺少一个必需的位置参数:'weights' - Shane S
@ShaneS 请确保您完全复制粘贴我的示例。def weighted_avg(group_df, whole_df, values, weights)有4个参数,在agg()中我也使用4个参数调用它。 - Andrej Kesely
2
如果我们不修改函数而是将 weighted_avg(dfr.loc[x.index], 'D', 'C') 传递给 lambda,那么可能更直观。 - user7864386
@enke 是的,那是另一个选项。我在我的答案中提到了它。 - Andrej Kesely

1

对于这种情况,我通常会添加计算过程中间阶段的列:

df['product'] = df['value'] * df['weight']
weighted_avg = sum(df['product']) / sum(df['weight'])

您可以像平常一样进行分组和子集选择:
df0 = df[df['group']==0]
df1 = df[df['group']==1]

并且针对每个组别分别计算weighted_avg


0

在你写的代码中

lambda x: weighted_avg(dfr, 'D', 'C')

这将计算整个表格 dfr 的加权平均值。

如果你将它改为

lambda group: weighted_avg(group, "D", "C")

那么我认为它可能会起作用。

(我已经将 lambda 变量的名称更改为 group,因为 x 不是很具有描述性)


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