Используйте pandas для группировки по столбцам, а затем создайте новый столбец на основе условия - PullRequest
0 голосов
/ 01 ноября 2018

Мне нужно воспроизвести с пандами то, что SQL делает так легко:

select
    del_month
    , sum(case when off0_on1 = 1 then 1 else 0 end) as on1
    , sum(case when off0_on1 = 0 then 1 else 0 end) as off0
from a1
group by del_month
order by del_month

Вот пример, иллюстративный кадр данных панд для работы:

a1 = pd.DataFrame({'del_month':[1,1,1,1,2,2,2,2], 'off0_on1':[0,0,1,1,0,1,1,1]})

Вот мои попытки воспроизвести вышеуказанный SQL с помощью панд. Первая строка работает. Вторая строка выдает ошибку:

a1['on1'] = a1.groupby('del_month')['off0_on1'].transform(sum)
a1['off0'] = a1.groupby('del_month')['off0_on1'].transform(sum(lambda x: 1 if x == 0 else 0))

Вот ошибка второй строки:

TypeError: 'function' object is not iterable

Этот мой предыдущий вопрос имел проблему с лямбда-функцией, которая была решена. Большая проблема заключается в том, как воспроизвести логику SQL «сумма (случай, когда)» для сгруппированных данных. Я ищу общее решение, так как мне нужно часто делать подобные вещи. Ответы на мой предыдущий вопрос предложили использовать map () внутри лямбда-функции, но следующие результаты для столбца «off0» не то, что мне нужно. Столбец "on1" - это то, что я хочу. Ответ должен быть одинаковым для всей группы (то есть "del_month").

enter image description here

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

При использовании get_dummies потребуется только один вызов groupby, что проще.

v = pd.get_dummies(df.pop('off0_on1')).groupby(df.del_month).transform(sum)
df = pd.concat([df, v.rename({0: 'off0', 1: 'on1'}, axis=1)], axis=1)

df
   del_month  off0  on1
0          1     2    2
1          1     2    2
2          1     2    2
3          1     2    2
4          2     1    3
5          2     1    3
6          2     1    3
7          2     1    3

Кроме того, в случае агрегирования, звоните sum напрямую, вместо использования apply:

(pd.get_dummies(df.pop('off0_on1'))
   .groupby(df.del_month)
   .sum()
   .rename({0: 'off0', 1: 'on1'}, axis=1))

           off0  on1
del_month           
1             2    2
2             1    3
0 голосов
/ 01 ноября 2018

Просто сложите Истины в ваших условных логических выражениях:

import pandas as pd

a1 = pd.DataFrame({'del_month':[1,1,1,1,2,2,2,2], 
                   'off0_on1':[0,0,1,1,0,1,1,1]})

a1['on1'] = a1.groupby('del_month')['off0_on1'].transform(lambda x: sum(x==1))    
a1['off0'] = a1.groupby('del_month')['off0_on1'].transform(lambda x: sum(x==0))

print(a1)    
#    del_month  off0_on1  on1  off0
# 0          1         0    2     2
# 1          1         0    2     2
# 2          1         1    2     2
# 3          1         1    2     2
# 4          2         0    3     1
# 5          2         1    3     1
# 6          2         1    3     1
# 7          2         1    3     1

Аналогично, вы можете сделать то же самое в SQL, если диалект поддерживает это, что большинство должно:

select
    del_month
    , sum(off0_on1 = 1) as on1
    , sum(off0_on1 = 0) as off0
from a1
group by del_month
order by del_month

И для репликации вышеупомянутого SQL в пандах, не используйте transform, но отправляйте несколько агрегатов в groupby().apply() вызове:

def aggfunc(x):
    data = {'on1': sum(x['off0_on1'] == 1),
            'off0': sum(x['off0_on1'] == 0)}

    return pd.Series(data)

g = a1.groupby('del_month').apply(aggfunc)

print(g)    
#            on1  off0
# del_month           
# 1            2     2
# 2            3     1
...