2014-10-05 36 views
19

Ho la seguente tabella. Voglio calcolare una media ponderata raggruppata per ogni data in base alla seguente formula. Posso farlo usando un codice convenzionale standard, ma partendo dal presupposto che questi dati siano in un dataframe panda, esiste un modo più semplice per raggiungere questo obiettivo piuttosto che attraverso l'iterazione?Calcolare la media ponderata usando un panda/dataframe

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))

+3

Nota che nel tuo esempio colonna 'valore' rappresenta in realtà i pesi, e il 'peso' colonna i valori da mediare ... – kadee

risposta

17

credo voglio farlo con due groupbys.

primo a calcolare il "media ponderata":

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 

Se si imposta questo come una colonna, è possibile GroupBy su di esso:

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

Ora la somma di questa colonna è il desiderato :

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

o potenzialmente:

01.235.164,106 mila
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 
+0

Nota: non sono al 100% come mi sento di riusare g quando si cambia df, a patto che non si stia mutando il tasto groupby, penso che sia pulito ... potenzialmente questo è controverso ?! IMO pandastico. –

+0

sono stato in grado di realizzare questo facendo qualcosa di simile, ma invece di trasformare, ho appena usato groupby (..). Sum(). C'è qualche vantaggio nell'uso della trasformazione? – mike01010

+0

@AndyHayden l'oggetto DataFrameGroupBy * dovrebbe * riflettere un oggetto mutato, ma in questo caso non stai mutando, quindi non è un grosso problema. – Jeff

11

Diamo prima creare l'esempio panda dataframe:

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) 

Poi, la media dei 'wt' ponderato da 'valore' e raggruppati per l'indice è ottenuta come:

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 , si può anche definire una funzione:

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 
+0

Mi piace molto questo aspetto (a causa della leggibilità), ci sono delle prestazioni significative tra questa e la soluzione di Andy Hayden? – erb

+2

È possibile che in questa riga: In [5]: df.groupby (df.index) .apply (lambda x: np.average (x.wt, pesi = x.valore)) x.wt e x.value dovrebbe essere cambiato? – prooffreader

+0

@prooffreader: come ho commentato [sopra] (http://stackoverflow.com/questions/26205922/calculate-weighted-average-using-a-pandas-dataframe/33054358#comment53928794_26205922): nell'esempio fornito dal richiedente, la colonna 'value' rappresenta effettivamente i pesi e la colonna 'wt' i valori da calcolare come media. – kadee

5

ho salvato la tabella nel file .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) 
Problemi correlati