【问题标题】:weighted average in pandas pivot_tablepandas pivot_table中的加权平均值
【发布时间】:2020-02-21 01:29:16
【问题描述】:

我正在尝试生成 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

我想按 Group 分组并返回一个新的权重(df.wt 的总和 -- easy peasy)和由 df.wt 加权的 df.val 的平均值来产生这个:


Group   weight  val
0   A   30  0.333
1   B   10  1.000

在实际应用程序中,有大量的 val 列和一个 weight 列以及我想要应用不同 aggfunc 的其他列。所以虽然我意识到我可以通过直接应用 groupby 来做到这一点,但它更混乱。有没有办法在 pivot_table 中滚动我自己的 aggfunc 来计算加权平均值?

【问题讨论】:

    标签: python pandas


    【解决方案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
    

    【讨论】:

    • 这很棒。是否有一种直接的方法可以将其扩展为对类似 val 的列的列表进行相同的加权平均?
    【解决方案2】:

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

    创建一个使用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
    

    【讨论】:

      猜你喜欢
      • 2016-05-23
      • 2018-10-02
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 2021-06-26
      • 1970-01-01
      • 2021-08-28
      • 2018-09-26
      相关资源
      最近更新 更多