python pandas 使用 groupby agg() 的加权平均值

python pandas weighted average with the use of groupby agg()

我希望能够在 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

问题: 加权平均值返回整个 table 而不是 'group' 列的值。我怎样才能得到分组工作的加权平均值?

我确实尝试将 groupby 放在 shown here 之类的函数中,但没有成功。 感谢您的观看。

您可以使用 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')

你写的地方 lambda x: weighted_avg(dfr, 'D', 'C')

这将计算 dfr 的加权平均值,即整个 table。

如果你把它改成 lambda group: weighted_avg(group, "D", "C")

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

(我已将 lambda 变量的名称更改为 group,因为 x 的描述性不强)

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

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

然后您可以像往常一样进行分组和 subset-selction:

df0 = df[df['group']==0]
df1 = df[df['group']==1]

并为每组分别计算weighted_avg