2015-11-11 21 views
5

ho te seguente panda dataframe:Calcolare la media ponderata con i panda dataframe

data_df = pd.DataFrame({'ind':['la','p','la','la','p','g','g','la'], 
         'dist':[10.,5.,7.,8.,7.,2.,5.,3.], 
         'diff':[0.54,3.2,8.6,7.2,2.1,1.,3.5,4.5], 
         'cas':[1.,2.,3.,4.,5.,6.,7.,8.]}) 

cioè

cas diff dist ind 
0 1 0.54 10 la 
1 2 3.20  5 p 
2 3 8.60  7 la 
3 4 7.20  8 la 
4 5 2.10  7 p 
5 6 1.00  2 g 
6 7 3.50  5 g 
7 8 4.50  3 la 

devo calcolare la media ponderata di tutte le colonne dove i pesi sono in ' dist 'colonna e raggruppare i valori per' ind '.

Per esempio per = 'la' e la colonna 'ind' 'diff':

((10*0.54)+(8.60*7)+(7.20*8)+(4.50*3))/(10+7+8+3) = 4.882143 

il risultato che voglio ottenere è la seguente

 cas  diff 
ind      
g 6.714286 2.785714 
la 3.107143 4.882143 
p 3.750000 2.558333 

che si ottiene moltiplicando ogni valore di ciascuna colonna per il valore corrispondente nella colonna 'dist', somma i risultati con lo stesso 'ind' e quindi dividendo il risultato per la somma di tutti i valori 'dist' corrispondenti allo stesso ind.

Ho pensato che questo sarebbe stato un compito facile fatto dal metodo "groupby" dataframe, ma in realtà è un po 'complicato.

Qualcuno può aiutarmi?

risposta

6

Si può ottenere all'interno dei gruppi pesi normalizzati utilizzando transform:

>>> df['weight'] = df['dist']/df.groupby('ind')['dist'].transform('sum') 
>>> df['weight'] 
0 0.357143 
1 0.416667 
2 0.250000 
3 0.285714 
4 0.583333 
5 0.285714 
6 0.714286 
7 0.107143 
Name: weight, dtype: float64 

Poi, basta moltiplicare questi peso dai valori, e prendere la somma:

>>> df['wcas'], df['wdiff'] = (df[n] * df['weight'] for n in ('cas', 'diff')) 
>>> df.groupby('ind')[['wcas', 'wdiff']].sum() 
     wcas  wdiff 
ind      
g 6.714286 2.785714 
la 3.107143 4.882143 
p 3.750000 2.558333 

Modifica: con mutazione sul posto:

>>> backup = df.copy()  # make a backup copy to mutate in place 
>>> cols = df.columns[:2] # cas, diff 
>>> df[cols] = df['weight'].values[:, None] * df[cols] 
>>> df.groupby('ind')[cols].sum() 
      cas  diff 
ind      
g 6.714286 2.785714 
la 3.107143 4.882143 
p 3.750000 2.558333 
+0

Questo funziona davvero! Grazie. L'unico problema è che il dataframe che ho scritto è solo un esempio, sto lavorando con big data e migliaia di colonne, quindi stavo cercando una soluzione in cui non dovessi scrivere i nomi delle colonne ... – Cecilia

+0

@ Cecilia puoi ottenere un elenco di colonne usando 'df.columns', e usalo come nella modifica –

+0

Grazie !!! Questa è la soluzione che stavo cercando :) – Cecilia