熊猫加权平均数据透视表

时间:2020-02-21 01:29:16

标签: python pandas

我正在尝试生成pandas数据透视表,该表计算一系列数据列中的值的平均值,这些数据列由固定权重列中的值加权,并努力寻找一种优雅而有效的方式来做到这一点。

>
df = pd.DataFrame([['A',10,1],['A',20,0],['B',10,1],['B',0,0]],columns=['Group','wt','val'])


Group   wt  val
0   A   10  1
1   A   20  0
2   B   10  1
3   B   0   0

我想按组分组并返回新的权重(df.wt的总和-easy peasy)和由df.wt加权的df.val的平均值,以得出以下结果:


Group   weight  val
0   A   30  0.333
1   B   10  1.000

在实际的应用程序中,有大量的val列和一个weight列,以及我要向其应用不同aggfuncs的其他列。因此,尽管我意识到我可以通过直接应用groupby来做到这一点,但它更麻烦。有没有一种方法可以在pivot_table中滚动我自己的agfunc,从而可以计算加权平均值?

2 个答案:

答案 0 :(得分:1)

这里是groupby的一种方法:

(df.assign(total=df.wt*df.val)
   .groupby('Group', as_index=False)
   .sum()
   .assign(val=lambda x: x['total']/x['wt'])
   .drop('total', axis=1)
)

输出:

  Group  wt       val
0     A  30  0.333333
1     B  10  1.000000

更新:对于所有val类列:

# toy data
df = pd.DataFrame([['A',10,1,1],['A',20,0,1],['B',10,1,2],['B',0,0,1]],
                  columns=['Group','wt','val_a', 'val_b'])
# grouping sum
new_df = (df.filter(like='val')  # filter val columns
           .mul(df.wt, axis=0)   # multiply with weights
           .assign(wt=df.wt)     # attach weight
           .groupby(df.Group).sum()
)

# loop over columns and divide the weight sum
new_df.apply(lambda x: x/new_df['wt'] if x.name != 'wt' else x)

输出:

          val_a  val_b  wt
Group                     
A      0.333333    1.0  30
B      1.000000    2.0  10

答案 1 :(得分:0)

这应该适用于多个数字列:

创建一个使用numpy average(包括权重)的函数。

对groupby中的组运行列表理解,并应用该功能

连接输出

df = pd.DataFrame([['A',10,1,2],['A',20,0,3],['B',10,1,2],['B',0,0,3]],columns=['Group','wt','val','vala'])




   Group    wt  val vala
0    A      10   1   2
1    A      20   0   3
2    B      10   1   2
3    B      0    0   3

#create function

def avg(group):

    df = pd.DataFrame()

    for col in group.columns.drop(['Group','wt']):

        A = group[col]
        B = group['wt']

        df['Group'] = group['Group'].unique()
        df['wt'] = B.sum()
        df[col] = np.average(A, weights=B)


    return df

#pipe function to the group in the list comprehension

 output = [group.pipe(avg) for name, group in df.groupby('Group')]

#concatenate dataframes

 pd.concat(output,ignore_index=True)


   Group    wt     val       vala
0   A      30   0.333333    2.666667
1   B      10   1.000000    2.000000