Вычислить средневзвешенное значение с помощью фрейма данных pandas
У меня есть следующий фрейм данных pandas:
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.]})
То есть
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
Мне нужно вычислить средневзвешенное значение всех столбцов, где веса находятся в столбце "dist", и сгруппировать значения по "ind".
Например для ' ind ' = 'la' и столбца 'diff':
((10*0.54)+(8.60*7)+(7.20*8)+(4.50*3))/(10+7+8+3) = 4.882143
Результат, который я хочу получить, следующий
cas diff
ind
g 6.714286 2.785714
la 3.107143 4.882143
p 3.750000 2.558333
Который получается путем умножения каждого значения каждого colums на соответствующее значение в столбце' dist', суммируем результаты с помощью то же самое "ind", а затем деление результата на сумму всех значений "dist", соответствующих одному и тому же ind.
Я думал, что это будет легкая задача, выполняемая методом dataframe 'groupby', но на самом деле это довольно сложно.
Может кто-то пожалуйста, помогите мне?
1 ответ:
Вы можете получить внутри групп нормализованные веса , используя
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Тогда вам просто нужно умножить эти веса на значения и взять сумму:
>>> 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
Правка: с мутацией на месте:
>>> 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
Comments