Вычислить средневзвешенное значение с помощью панды / dataframe

20

У меня есть следующая таблица. Я хочу рассчитать средневзвешенное значение, сгруппированное по каждой дате, исходя из приведенной ниже формулы. Я могу сделать это с использованием стандартного обычного кода, но если предположить, что эти данные находятся в кадре данных pandas, есть ли более простой способ добиться этого, а не через итерацию?

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

    
задан mike01010 05.10.2014 в 20:36
источник
  • Обратите внимание, что в вашем примере столбец «значение» фактически представляет веса, а столбец «wt» - значения, которые необходимо усреднить ... –  kadee 10.10.2015 в 15:09

4 ответа

17

Думаю, я сделал бы это с двумя groupbys.

Сначала вычислить «средневзвешенное значение»:

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

Если вы установите это как столбец, вы можете группировать его:

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
    
ответ дан Andy Hayden 05.10.2014 в 21:56
  • Примечание: я не на 100%, как я чувствую, что повторно использую g при мутировании df, если вы не мутируете ключ группы. Я думаю, что это опрятно ... возможно, это противоречиво ?! ИМО пандастичный. –  Andy Hayden 05.10.2014 в 21:59
  • я смог выполнить это, делая что-то подобное, но вместо преобразования я просто использовал groupby (..). sum (). Есть ли преимущества в использовании преобразования? –  mike01010 05.10.2014 в 22:25
  • @AndyHayden объект DataFrameGroupBy будет отображать мутированный объект, но в этом случае вы не мутируете, так что неважно. –  Jeff 05.10.2014 в 22:44
  • Когда я пытаюсь вставить это в один и тот же фрейм данных, значения - это все NAN. Я думаю, что это связано с тем, что агрегирование относится к дате, но датафрейм индексируется по дате и идентификатору. так что это не сработает: df ['w_avg'] = g.wa.sum (). Как это решить? –  mike01010 06.10.2014 в 00:06
  • @ mike01010 transform распространяет результат по группе, полезен, если вы используете его позже. Вставка с помощью NaN - это именно то, что нужно преобразованию (оно соответствует исходному индексу). –  Andy Hayden 06.10.2014 в 00:14
11

Давайте сначала создадим примерный фрейм данных pandas:

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)

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

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
    
ответ дан kadee 10.10.2015 в 15:09
  • Мне нравится это намного лучше (из-за удобочитаемости), есть ли какие-то значительные результаты между этим и решением Энди Хейдена? –  erb 19.10.2015 в 13:47
  • Возможно ли, что в этой строке: В [5]: df.groupby (df.index) .apply (lambda x: np.average (x.wt, weight = x.value)) x.wt и x значение должно быть переключено? –  prooffreader 09.02.2016 в 16:49
  • @prooffreader: Как я уже отмечал выше: в примере, указанном азбуком, столбец «значение» фактически представляет веса, а столбец «wt» - усредненные значения. –  kadee 12.04.2016 в 12:02
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)
    
ответ дан user15051990 05.03.2016 в 07:39
5

Я чувствую, что это элегантное решение этой проблемы :( Pandas Функция агрегации DataFrame с использованием нескольких столбцов )

grouped = df.groupby('Date')

def wavg(group):
    d = group['value']
    w = group['wt']
    return (d * w).sum() / w.sum()

grouped.apply(wavg)
    
ответ дан Anish Sugathan 28.10.2015 в 14:18