Выполнять взвешенное соотношение только для строк с дублированным идентификатором

#pandas #numpy

#pandas #numpy

Вопрос:

Предположим, у меня следующая ситуация:

Фрейм данных, в котором первый столбец ['ID'] в конечном итоге будет иметь дублированные значения.

 import pandas as pd
df = pd.DataFrame({"ID": [1,2,3,4,4,5,5,5,6,6], 
                  "l_1": [1,1,1,1,2,1,1,3,2,1], 
                  "l_2": [10,12,32,45,0,20,0,0,20,0],
                  "l_3": [5,12,32,33,0,10,0,0,5,0]})


ID  l_1 l_2 l_3
1   1   10  5
2   1   12  12
3   1   32  32
4   1   45  33
4   2   0   0
5   1   20  10
5   1   0   0
5   3   0   0
6   2   20  5
6   1   0   0
 

Я пытаюсь сделать следующее:

1 — Выберите только строки с дублированными идентификаторами

2 — Заменить строки l_2 и l_3 соответственно на:

  • (сумма l_2 (сгруппированных по идентификаторам), деленная на сумму l_1 (сгруппированных по идентификаторам)) * l_1
  • (сумма l_3 (сгруппированных по идентификаторам), деленная на сумму l_1 (сгруппированных по идентификаторам)) * l_1

3- Объединить эти дублированные строки идентификаторов обратно в исходный фрейм данных

Ожидаемый результат:

 ID  l_1     l_2      l_3
1   1   10.000000   5.000000
2   1   12.000000   12.000000
3   1   32.000000   32.000000
4   1   15.000000   11.000000
4   2   30.000000   22.000000
5   1   4.000000    2.000000
5   1   4.000000    2.000000
5   3   12.000000   6.000000
6   2   13.333333   3.333333
6   1   6.666667    1.666667
 

Есть ли простой способ с использованием pandas или numpy для достижения этой цели?

Я мог бы просто выполнить все эти шаги:

 df1 = df[df.duplicated(subset=['ID'], keep=False)].groupby('ID')[['l_1', 'l_2', 'l_3']].sum().reset_index()
df1['ratio_1'] = df1['l_2'] / df1['l_1']
df1['ratio_2'] = df1['l_3'] / df1['l_1']
df = df.merge(df1[['ID','ratio_1', 'ratio_2']], on=['ID'], how='left')
df['l_2'] = np.where(df['ratio_1'].isnull(), df['l_2'], df['ratio_1']*df['l_1'])
df['l_3'] = np.where(df['ratio_2'].isnull(), df['l_3'], df['ratio_2']*df['l_1'])
df.drop(columns=['ratio_1', 'ratio_2'], inplace=True)
 

Ответ №1:

Давайте попробуем:

 s = df.groupby('ID').transform('sum')

s.div(s['l_1'], axis='rows').mul(df['l_1'], axis='rows')
 

Вывод:

    l_1        l_2        l_3
0  1.0  10.000000   5.000000
1  1.0  12.000000  12.000000
2  1.0  32.000000  32.000000
3  1.0  15.000000  11.000000
4  2.0  30.000000  22.000000
5  1.0   4.000000   2.000000
6  1.0   4.000000   2.000000
7  3.0  12.000000   6.000000
8  2.0  13.333333   3.333333
9  1.0   6.666667   1.666667
 

Комментарии:

1. Большое вам спасибо @Quang Hoang. Мне очень понравился ваш подход.