Calcular el promedio ponderado utilizando un dataframe / pandas

Tengo la siguiente tabla. Quiero calcular un promedio ponderado agrupado por cada fecha en base a la siguiente fórmula. Puedo hacer esto usando algún código convencional estándar, pero suponiendo que estos datos se encuentran en un dataframe de pandas, ¿hay alguna forma más fácil de lograr esto que mediante la iteración?

Date ID wt value w_avg 01/01/2012 100 0.50 60 0.791666667 01/01/2012 101 0.75 80 01/01/2012 102 1.00 100 01/02/2012 201 0.50 100 0.722222222 01/02/2012 202 1.00 80 

01/01/2012 w_avg = 0.5 * (60 / sum (60,80,100)) + .75 * (80 / sum (60,80,100)) + 1.0 * (100 / sum (60,80,100))

01/02/2012 w_avg = 0.5 * (100 / sum (100,80)) + 1.0 * (80 / sum (100,80))

Creo que haría esto con dos groupbys.

Primero en calcular el “promedio ponderado”:

 In [11]: g = df.groupby('Date') In [12]: df.value / g.value.transform("sum") * df.wt Out[12]: 0 0.125000 1 0.250000 2 0.416667 3 0.277778 4 0.444444 dtype: float64 

Si establece esto como una columna, puede agruparse sobre él:

 In [13]: df['wa'] = df.value / g.value.transform("sum") * df.wt 

Ahora la sum de esta columna es la deseada:

 In [14]: g.wa.sum() Out[14]: Date 01/01/2012 0.791667 01/02/2012 0.722222 Name: wa, dtype: float64 

o potencialmente:

 In [15]: g.wa.transform("sum") Out[15]: 0 0.791667 1 0.791667 2 0.791667 3 0.722222 4 0.722222 Name: wa, dtype: float64 

Primero creamos el dataframe pandas de ejemplo:

 In [1]: import numpy as np In [2]: import pandas as pd In [3]: index = pd.Index(['01/01/2012','01/01/2012','01/01/2012','01/02/2012','01/02/2012'], name='Date') In [4]: df = pd.DataFrame({'ID':[100,101,102,201,202],'wt':[.5,.75,1,.5,1],'value':[60,80,100,100,80]},index=index) 

Luego, el promedio de ‘wt’ ponderado por ‘valor’ y agrupado por el índice se obtiene como:

 In [5]: df.groupby(df.index).apply(lambda x: np.average(x.wt, weights=x.value)) Out[5]: Date 01/01/2012 0.791667 01/02/2012 0.722222 dtype: float64 

Alternativamente, también se puede definir una función:

 In [5]: def grouped_weighted_avg(values, weights, by): ...: return (values * weights).groupby(by).sum() / weights.groupby(by).sum() In [6]: grouped_weighted_avg(values=df.wt, weights=df.value, by=df.index) Out[6]: Date 01/01/2012 0.791667 01/02/2012 0.722222 dtype: float64 

Guardé la tabla en el archivo .csv

 df=pd.read_csv('book1.csv') grouped=df.groupby('Date') g_wavg= lambda x: np.average(x.wt, weights=x.value) grouped.apply(g_wavg) 

Creo que la siguiente es una solución elegante para este problema desde: ( función agregada de Pandas DataFrame usando varias columnas )

 grouped = df.groupby('Date') def wavg(group): d = group['value'] w = group['wt'] return (d * w).sum() / w.sum() grouped.apply(wavg)