Панды - сгруппировать две функции - PullRequest
0 голосов
/ 15 октября 2018

Я пытался получить сперму на объекте группового панды.Мне нужно, чтобы сумма была сдвинута на единицу, что достигается с помощью shift ().Однако выполнение обеих этих функций на одном объекте groupby дает некоторые нежелательные результаты:

df = pd.DataFrame({'A': [1, 1, 1, 2, 2, 2],
                   'B': [2, 3, 5, 2, 3, 5]})

df.groupby('A').cumsum().shift()

, что дает:

      B
0   NaN
1   2.0
2   5.0
3  10.0
4   2.0
5   5.0

Т.е. последнее значение cumsum () в группе 1смещено в первое значение группы 2. Я хочу, чтобы эти группы оставались разделенными и получали:

      B
0   NaN
1   2.0
2   5.0
3   NaN
4   2.0
5   5.0

Но я не уверен, как заставить обе функции работать с объектом groupbyвместе взятые.Больше нигде не могу найти этот вопрос.Играли с Аггом, но, похоже, не сработали.Любая помощь будет оценена.

Ответы [ 2 ]

0 голосов
/ 15 октября 2018

Результатом вашей первой операции df.groupby('A').cumsum() является обычный фрейм данных.Это эквивалентно df.groupby('A')[['B']].cumsum(), но Pandas удобно позволяет вам пропустить индексную часть [['B']].

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

res = df.groupby('A').cumsum().groupby(df['A']).shift()

Но, как вы можете видеть, это повторяет операцию группировки и будет неэффективным.Вместо этого вы можете определить одну функцию, которая объединяет cumsum и shift в правильном порядке, а затем применить эту функцию к одному GroupBy объекту.Определение этой единственной функции известно как композиция функции , и она не является родной для Python.Вот несколько альтернатив:

Определение новой именованной функции

Это явное и рекомендуемое решение:

def cum_shift(x):
    return x.cumsum().shift()

res1 = df.groupby('A')[['B']].apply(cum_shift)

Определение анонимной lambda функции

Однострочная версия вышеприведенного:

res2 = df.groupby('A')[['B']].apply(lambda x: x.cumsum().shift())

Используйте библиотеку, которая составляет

Это чисто функциональное решение;например, через третьих лиц toolz:

from toolz import compose
from operator import methodcaller

cumsum_shift_comp = compose(methodcaller('shift'), methodcaller('cumsum'))

res3 = df.groupby('A')[['B']].apply(cumsum_shift_comp)

Все вышеперечисленное дает эквивалентный результат:

assert res.equals(res1) and res1.equals(res2) and res2.equals(res3)

print(res1)

     B
0  NaN
1  2.0
2  5.0
3  NaN
4  2.0
5  5.0
0 голосов
/ 15 октября 2018

Используйте lambda function с GroupBy.apply, также необходимо определить столбцы в списке после groupby для обработки:

df['B'] = df.groupby('A')['B'].apply(lambda x: x.cumsum().shift())
print (df)
   A    B
0  1  NaN
1  1  2.0
2  1  5.0
3  2  NaN
4  2  2.0
5  2  5.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...