2014-10-05 6 views
19

У меня есть следующая таблица. Я хочу рассчитать средневзвешенное значение, сгруппированное по каждой дате, исходя из приведенной ниже формулы. Я могу сделать это с использованием стандартного обычного кода, но если предположить, что эти данные находятся в кадре данных pandas, есть ли более простой способ добиться этого, а не через итерацию?Рассчитать средневзвешенное значение с использованием панды/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/сумма (60,80,100)) + 0,75 * (80/сумма (60,80,100)) + 1,0 * (100/сумма (60, 80.100))

01/02/2012 w_avg = 0,5 * (100/сумма (100,80)) + 1,0 * (80/сумма (100,80))

+3

замечание, что в вашем примере столбец «значение» на самом деле представляет веса, и «вес» столбец значения, которые нужно усреднить ... – kadee

ответ

17

я бы сделать это с две группы.

Во-первых, чтобы вычислить «взвешенное среднее»:

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 

Если вы установите в качестве колонки, вы можете GroupBy над ним:

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

Теперь сумма этого столбца является искомым :

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

или потенциально:

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

Примечание: я не на 100%, как я чувствую, что повторно использую g при мутации df, если вы не мутируете ключ группы, я думаю, что он опрятен ... возможно, это противоречиво ?! ИМО пандастичный. –

+0

Мне удалось выполнить это с помощью чего-то подобного, но вместо преобразования я просто использовал groupby (..). Sum(). Есть ли преимущества в использовании преобразования? – mike01010

+0

@ AndyHayden Объект DataFrameGroupBy * будет * отражать мутированный объект, но в этом случае вы не мутируете, так что неважно. – Jeff

11

Давайте сначала создать пример панд 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) 

Затем среднее значение «мас» взвешенных по «значение» и сгруппированы по индексу получается как:

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 

В качестве альтернативы , можно также определить функцию:

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

Мне нравится это намного лучше (из-за удобочитаемости), есть ли какие-либо существенные результаты между этим и решением Энди Хайдена? – erb

+2

Возможно ли, что в этой строке: В [5]: df.groupby (df.index) .apply (lambda x: np.average (x.wt, weight = x.value)) x.wt и x.значение должно быть переключено? – prooffreader

+0

@prooffreader: Как я прокомментировал [выше] (http://stackoverflow.com/questions/26205922/calculate-weighted-average-using-a-pandas-dataframe/33054358#comment53928794_26205922): в примере, указанном автором, столбец «значение» фактически представляет веса, а столбец «wt» - усредненные значения. – kadee

5

Я сохранил таблицу в файле .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) 
Смежные вопросы