Подтвердить что ты не робот

Как использовать групповое преобразование через несколько столбцов

У меня есть большой фреймворк данных, и я группирую от одного до n столбцов и хочу применить функцию к этим группам через два столбца (например, foo и bar).

Здесь примерный кадр:

foo_function = lambda x: np.sum(x.a+x.b)

df = pd.DataFrame({'a':[1,2,3,4,5,6],
                   'b':[1,2,3,4,5,6],
                   'c':['q', 'q', 'q', 'q', 'w', 'w'],  
                   'd':['z','z','z','o','o','o']})

# works with apply, but I want transform:
df.groupby(['c', 'd'])[['a','b']].apply(foo_function)
# transform doesn't work!
df.groupby(['c', 'd'])[['a','b']].transform(foo_function)
TypeError: cannot concatenate a non-NDFrame object

Но transform, по-видимому, не может объединить несколько столбцов вместе, потому что он смотрит на каждый столбец отдельно (в отличие от приложения). Какая следующая лучшая альтернатива с точки зрения скорости/элегантности? например Я мог бы использовать apply, а затем создать df['new_col'] с помощью pd.match, но это потребует сопоставления иногда нескольких столбцов groupw (col1 и col2), которые кажутся действительно взломанными/будут принимать достаточное количество кода.

- > Есть ли функция, подобная groupby(). transform, которая может использовать функции, которые работают над несколькими столбцами? Если этого не существует, какой лучший взлом?

4b9b3361

Ответ 1

Вместо этого, если вам нужно выполнить групповое вычисление по нескольким столбцам, сначала выполните вычисления с несколькими столбцами, а затем groupby:

df = pd.DataFrame({'a':[1,2,3,4,5,6],
                   'b':[1,2,3,4,5,6],
                   'c':['q', 'q', 'q', 'q', 'w', 'w'],  
                   'd':['z','z','z','o','o','o']})
df['e'] = df['a'] + df['b']
df['e'] = (df.groupby(['c', 'd'])['e'].transform('sum'))
print(df)

дает

   a  b  c  d   e
0  1  1  q  z  12
1  2  2  q  z  12
2  3  3  q  z  12
3  4  4  q  o   8
4  5  5  w  o  22
5  6  6  w  o  22

Оригинальный ответ:

Сообщение об ошибке:

TypeError: cannot concatenate a non-NDFrame object

предполагает, что для конкатенации foo_function должен возвращать NDFrame (например, Series или DataFrame). Если вы вернете серию, то:

In [99]: df.groupby(['c', 'd']).transform(lambda x: pd.Series(np.sum(x['a']+x['b'])))
Out[99]: 
    a   b
0  12  12
1  12  12
2  12  12
3   8   8
4  22  22
5  22  22

Ответ 2

Как я читаю вопрос, вы хотите иметь возможность делать что-то произвольное с обоими значениями из обоих столбцов. Вам просто нужно убедиться, что вы вернете рамку данных того же размера, что и вы передали. Я думаю, что лучший способ - просто создать новый столбец, например:

df = pd.DataFrame({'a':[1,2,3,4,5,6],
                   'b':[1,2,3,4,5,6],
                   'c':['q', 'q', 'q', 'q', 'w', 'w'],  
                   'd':['z','z','z','o','o','o']})
df['e']=0

def f(x):
    y=(x['a']+x['b'])/sum(x['b'])
    return pd.DataFrame({'e':y,'a':x['a'],'b':x['b']})

df.groupby(['c','d']).transform(f)

:

    a   b   e
0   1   1   0.333333
1   2   2   0.666667
2   3   3   1.000000
3   4   4   2.000000
4   5   5   0.909091
5   6   6   1.090909

Если у вас очень сложный фреймворк, вы можете выбрать свои столбцы (например, df.groupby(['c'])['a','b','e'].transform(f))

Это конечно выглядит очень неэлегантным для меня, но все еще намного быстрее, чем apply на больших наборах данных.

Другой альтернативой является использование set_index для захвата всех столбцов, которые вам нужны, а затем передать только один столбец в transform.