groupby加权平均值和pandas数据帧中的总和

时间:2015-07-20 15:55:40

标签: python r pandas

我有一个数据框,

    Out[78]: 
   contract month year  buys  adjusted_lots    price
0         W     Z    5  Sell             -5   554.85
1         C     Z    5  Sell             -3   424.50
2         C     Z    5  Sell             -2   424.00
3         C     Z    5  Sell             -2   423.75
4         C     Z    5  Sell             -3   423.50
5         C     Z    5  Sell             -2   425.50
6         C     Z    5  Sell             -3   425.25
7         C     Z    5  Sell             -2   426.00
8         C     Z    5  Sell             -2   426.75
9        CC     U    5   Buy              5  3328.00
10       SB     V    5   Buy              5    11.65
11       SB     V    5   Buy              5    11.64
12       SB     V    5   Buy              2    11.60

我需要一个adjust_lots的总和,价格是加权平均值,价格和ajusted_lots,按所有其他列分组,即。按(合同,月份,年份和购买)分组

使用dplyr通过以下代码实现对R的类似解决方案,但无法在pandas中执行相同操作。

> newdf = df %>%
  select ( contract , month , year , buys , adjusted_lots , price ) %>%
  group_by( contract , month , year ,  buys) %>%
  summarise(qty = sum( adjusted_lots) , avgpx = weighted.mean(x = price , w = adjusted_lots) , comdty = "Comdty" )

> newdf
Source: local data frame [4 x 6]

  contract month year comdty qty     avgpx
1        C     Z    5 Comdty -19  424.8289
2       CC     U    5 Comdty   5 3328.0000
3       SB     V    5 Comdty  12   11.6375
4        W     Z    5 Comdty  -5  554.8500

是否可以通过groupby或任何其他解决方案?

6 个答案:

答案 0 :(得分:67)

要将多个函数传递给groupby对象,需要传递一个字典,其中包含与列对应的聚合函数:

# Define a lambda function to compute the weighted mean:
wm = lambda x: np.average(x, weights=df.loc[x.index, "adjusted_lots"])

# Define a dictionary with the functions to apply for a given column:
f = {'adjusted_lots': ['sum'], 'price': {'weighted_mean' : wm} }

# Groupby and aggregate with your dictionary:
df.groupby(["contract", "month", "year", "buys"]).agg(f)

                         adjusted_lots         price
                                   sum weighted_mean
contract month year buys                            
C        Z     5    Sell           -19    424.828947
CC       U     5    Buy              5   3328.000000
SB       V     5    Buy             12     11.637500
W        Z     5    Sell            -5    554.850000

你可以在这里看到更多:

在这里的类似问题中:

希望这有帮助

答案 1 :(得分:3)

按groupby(...)进行加权平均.applied(...)可能非常慢(100x来自以下)。 在this thread上查看我的答案(和其他人)。

def weighted_average(df,data_col,weight_col,by_col):
    df['_data_times_weight'] = df[data_col]*df[weight_col]
    df['_weight_where_notnull'] = df[weight_col]*pd.notnull(df[data_col])
    g = df.groupby(by_col)
    result = g['_data_times_weight'].sum() / g['_weight_where_notnull'].sum()
    del df['_data_times_weight'], df['_weight_where_notnull']
    return result

答案 2 :(得分:2)

这样做会不会简单得多。

  1. 将(adjusted_lots * price_weighted_mean)乘以新列“ X”
  2. 将groupby()。sum()用于“ X”和“ adjusted_lots”列以获取 分组df df_grouped
  3. 将df_group上的加权平均值计算为 df_grouped ['X'] / df_grouped ['adjusted_lots']

答案 3 :(得分:1)

使用熊猫聚合函数的解决方案将在以后的熊猫(0.22版)中弃用:

FutureWarning: using a dict with renaming is deprecated and will be removed in a future 
version return super(DataFrameGroupBy, self).aggregate(arg, *args, **kwargs)

使用groupby应用并返回系列以重命名列,如以下讨论: Rename result columns from Pandas aggregation ("FutureWarning: using a dict with renaming is deprecated")

def my_agg(x):
    names = {'weighted_ave_price': (x['adjusted_lots'] * x['price']).sum()/x['adjusted_lots'].sum()}
    return pd.Series(names, index=['weighted_ave_price'])

产生相同的结果:

>df.groupby(["contract", "month", "year", "buys"]).apply(my_agg)

                          weighted_ave_price
contract month year buys                    
C        Z     5    Sell          424.828947
CC       U     5    Buy          3328.000000
SB       V     5    Buy            11.637500
W        Z     5    Sell          554.850000

答案 4 :(得分:0)

使用 datar,您无需学习 Pandas API 即可转换您的 R 代码:

$update = New-ScheduledTaskSettingsSet -StartWhenAvailable 
Set-ScheduledTask -TaskName 'Adobe Acrobat Update Task' -Settings $update

我是包的作者。如果您有任何问题,请随时提交问题。

答案 5 :(得分:0)

ErnestScribbler 的回答比公认的解决方案快得多。这是一个多元模拟:

def weighted_average(df,data_col,weight_col,by_col):
    ''' Now data_col can be a list of variables '''
    df_data = df[data_col].multiply(df[weight_col], axis='index')
    df_weight = pd.notnull(df[data_col]).multiply(df[weight_col], axis='index')
    df_data[by_col] = df[by_col]
    df_weight[by_col] = df[by_col]    
    result = df_data.groupby(by_col).sum() / df_weight.groupby(by_col).sum()
    return result