Python панды, эквивалентные R groupby мутировать

Итак, в R, когда у меня есть кадр данных, состоящий из 4 столбцов, назовите его df и я хочу вычислить отношение по суммированному произведению группы, я могу это сделать так:

// generate data
df = data.frame(a=c(1,1,0,1,0),b=c(1,0,0,1,0),c=c(10,5,1,5,10),d=c(3,1,2,1,2));
| a   b   c    d |
| 1   1   10   3 |
| 1   0   5    1 |
| 0   0   1    2 |
| 1   1   5    1 |
| 0   0   10   2 |
// compute sum product ratio
df = df%>% group_by(a,b) %>%
      mutate(
          ratio=c/sum(c*d)
      );
| a   b   c    d  ratio |
| 1   1   10   3  0.286 |
| 1   1   5    1  0.143 |
| 1   0   5    1  1     |
| 0   0   1    2  0.045 |
| 0   0   10   2  0.454 |

Но в python мне нужно прибегнуть к циклам. Я знаю, что должен быть более элегантный способ, чем исходные петли на питоне, у кого есть идеи?

Ответ 1

Это можно сделать с помощью аналогичного синтаксиса с groupby() и apply():

df['ratio'] = df.groupby(['a','b'], group_keys=False).apply(lambda g: g.c/(g.c * g.d).sum())

введите описание изображения здесь

Ответ 2

В соответствии с этим потоком на pandas github мы можем использовать метод transform() для воспроизведения комбинации dplyr::groupby() и dplyr::mutate(). Для этого примера это будет выглядеть следующим образом:

df = pd.DataFrame(
    dict(
        a=(1 , 1, 0, 1, 0 ), 
        b=(1 , 0, 0, 1, 0 ),
        c=(10, 5, 1, 5, 10),
        d=(3 , 1, 2, 1, 2 ),
    )
).assign(
    prod_c_d = lambda x: x['c'] * x['d'], 
    ratio    = lambda x: x['c'] / (x.groupby(['a','b']).transform('sum')['prod_c_d'])
)

В этом примере используется цепочка метода панд. Подробнее о том, как использовать цепочку методов для репликации рабочих процессов dplyr, см. в этом блоге.

Метод с использованием apply() и groupby() не работает для меня, потому что он, кажется, не адаптируется. Например, это не сработает, если мы удалим g.c/ из лямбда-выражения.

df['ratio'] = df.groupby(['a','b'], group_keys=False)\
    .apply(lambda g: (g.c * g.d).sum() )