Pandas сгруппировать и изменить / переназначить один элемент - PullRequest
1 голос
/ 26 марта 2020

Я хочу groupby для данного кадра данных, а затем для каждой группы для данного столбца p перезаписать значение его последнего элемента (каждой группы) на 1 - sum(p[:-1])sum, являющимся суммой все элементы, кроме последнего).

Обратите внимание, что после выполнения операции сумма всех значений в p для каждой группы равна 1.

Например, для этого входного кадра данных (группировка по c1 и c2):

  c1 c2    p
0  x  a  0.4
1  y  a  0.2
2  x  a  0.3
3  y  b  0.6

ожидаемый результат будет:

  c1 c2    p
0  x  a  0.4
1  y  a  1.0
2  x  a  0.6
3  y  b  1.0

Мне удалось выполнить операцию, используя for l oop:

for _, g in df.groupby(['c1', 'c2']):
    df.loc[g.tail(1).index, 'p'] = 1 - g['p'][:-1].sum()

но я ищу более элегантный способ сделать это, без явного зацикливания каждой группы .

Я попробовал это:

>>> df.loc[df.groupby(['c1', 'c2']).tail(1).index, 'p']

1    0.2
2    0.3
3    0.6

>>> 1 - df.groupby(['c1', 'c2']).apply(lambda x: x.iloc[:-1].sum())['p']

c1  c2
x   a     0.6
y   a     1.0
    b     1.0

Но я не знаю, как собрать эти выходные данные, если их индексы отличаются.

1 Ответ

1 голос
/ 27 марта 2020

Вот возможное однострочное решение:

df.groupby(['c1', 'c2']).apply(
        lambda x: x.assign(p=x['p'][:-1].tolist()+[1 - x.iloc[:-1].sum()['p']])
).reset_index(level=[0,1], drop=True)

Чтобы сделать приведенный выше код более читабельным, вот почти эквивалентная версия моего однострочного решения:

def func(row):
    result = 1 - row.iloc[:-1].sum()['p']
    row['p'].iloc[-1] = result
    return row

df.groupby(['c1', 'c2']).apply(func)

Имея в виду эти решения, я не совсем уверен, почему вы не хотите использовать вызов .groupby в явном python for-l oop. Я догадываюсь, что явный python for-l oop был бы более чем достаточным, но я не знаю вашего конкретного c варианта использования / данных. Я настоятельно рекомендую провести некоторые сравнения скорости, используя %timeit с вашими указанными c данными, так как я думаю, что это поможет пролить свет на то, какой подход вы в конечном итоге используете.

...