применение нескольких функций при преобразовании в pandas

#python #r #pandas #dplyr

#python #pandas #преобразование

Вопрос:

После groupby , при использовании agg , если передается dict of columns:functions , функции будут применены в соответствующих столбцах. Тем не менее, этот синтаксис не работает с transform . Есть ли другой способ применить несколько функций в transform ?

Давайте приведем пример:

 import pandas as pd
df_test = pd.DataFrame([[1,2,3],[1,20,30],[2,30,50],[1,2,33],[2,4,50]],columns = ['a','b','c'])
Out[1]:
    a   b   c
0   1   2   3
1   1   20  30
2   2   30  50
3   1   2   33
4   2   4   50

def my_fct1(series):
    return series.mean()

def my_fct2(series):
    return series.std()

df_test.groupby('a').agg({'b':my_fct1,'c':my_fct2})

Out[2]:
    c   b
a       
1   16.522712   8
2   0.000000    17
  

Предыдущий пример показывает, как применять разные функции к разным столбцам в agg , но если мы хотим преобразовать столбцы без их агрегирования, agg его больше нельзя использовать. Поэтому:

 df_test.groupby('a').transform({'b':np.cumsum,'c':np.cumprod})
Out[3]:
TypeError: unhashable type: 'dict'
  

Как мы можем выполнить такое действие со следующим ожидаемым результатом:

     a   b   c
0   1   2   3
1   1   22  90
2   2   30  50
3   1   24  2970
4   2   34  2500
  

Ответ №1:

Вы все еще можете использовать dict, но с небольшим взломом:

 df_test.groupby('a').transform(lambda x: {'b': x.cumsum(), 'c': x.cumprod()}[x.name])
Out[427]: 
    b     c
0   2     3
1  22    90
2  30    50
3  24  2970
4  34  2500
  

Если вам нужно сохранить столбец a, вы можете сделать:

 df_test.set_index('a')
       .groupby('a')
       .transform(lambda x: {'b': x.cumsum(), 'c': x.cumprod()}[x.name])
       .reset_index()
Out[429]: 
   a   b     c
0  1   2     3
1  1  22    90
2  2  30    50
3  1  24  2970
4  2  34  2500
  

Другой способ — использовать if else для проверки имен столбцов:

 df_test.set_index('a')
       .groupby('a')
       .transform(lambda x: x.cumsum() if x.name=='b' else x.cumprod())
       .reset_index()
  

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

1. Каким было бы решение в случае, если groupby содержит более одного столбца?

Ответ №2:

Я думаю, что сейчас (pandas 0.20.2) функция transform не реализована с dict именами столбцов с такими функциями, как agg .

Если функции возвращают Series одинаковую длину:

 df1 = df_test.set_index('a').groupby('a').agg({'b':np.cumsum,'c':np.cumprod}).reset_index()
print (df1)
   a     c   b
0  1     3   2
1  1    90  22
2  2    50  30
3  1  2970  24
4  2  2500  34
  

Но если требуется большая разная длина join :

 df2 = df_test[['a']].join(df_test.groupby('a').agg({'b':my_fct1,'c':my_fct2}), on='a')
print (df2)
   a          c   b
0  1  16.522712   8
1  1  16.522712   8
2  2   0.000000  17
3  1  16.522712   8
4  2   0.000000  17
  

Ответ №3:

С обновлениями в Pandas вы можете использовать assign метод наряду с transform либо для добавления новых столбцов, либо для замены существующих столбцов новыми значениями :

 grouper = df_test.groupby("a")

df_test.assign(b=grouper["b"].transform("cumsum"), 
               c=grouper["c"].transform("cumprod"))

    a   b   c
0   1   2   3
1   1   22  90
2   2   30  50
3   1   24  2970
4   2   34  2500