Как выполнить pandas cumsum, пропуская строки, которые дублируются в другом поле?

Я пытаюсь использовать функцию pandas.cumsum(), но таким образом, чтобы игнорировать строки со значением в столбце ID, который дублируется, и, в частности, добавлять только последнее значение к накопительной сумме, игнорируя все предыдущие значения. Пример кода ниже (я не смог поделиться настоящим кодом, предназначенным для работы).

import pandas as pd, numpy as np
import random as rand
id = ['a','b','c','a','b','e','f','a','b','k']
value = [12,14,3,13,16,7,4,6,10,18]

df = pd.DataFrame({'id':id, 'value':value})
df["cumsum_of_value"] = df['value'].cumsum()
df["desired_output"] = [
    12,26,29,30,32,39,43,36,30,48
]
df["comments"] = [""]*len(df)
df.loc[df.index==0, "comments"] = "standard cumsum"
df.loc[df.index==1, "comments"] = "standard cumsum"
df.loc[df.index==2, "comments"] = "standard cumsum"
df.loc[df.index==3, "comments"] = "cumsum of rows 1-3, ignore row 0"
df.loc[df.index==4, "comments"] = "cumsum of rows 2-4, ignore rows 0, 1"
df.loc[df.index==5, "comments"] = "cumsum of rows 2-5, ignore rows 0, 1"
df.loc[df.index==6, "comments"] = "cumsum of rows 2-6, ignore rows 0, 1"
df.loc[df.index==7, "comments"] = "cumsum of rows 2,4-7, ignore rows 0, 1, 3"
df.loc[df.index==8, "comments"] = "cumsum of rows 2,5-8, ignore rows 0, 1, 3, 4"
df.loc[df.index==9, "comments"] = "cumsum of rows 2,5-9, ignore rows 0, 1, 3, 4"
print(df)

В этом примере в столбце идентификатора имеется семь (7) уникальных значений (a, b, c,d, e, f, g), поэтому совокупная сумма должна суммировать максимум семь (7) записей в качестве выходных данных. в любом ряду.

Возможно ли это, используя комбинации таких функций, как cumsum(), groupby(), Duplied(), drop_duulates(), и избегая использования итеративного цикла?

Я попробовал следующее

df["duped"] = np.where(df["id"].duplicated(keep='last'),0,1)
df["value_duped"] = df["duped"] * df["value"]
df["desired_output_attempt"] = df["cumsum_of_value"] - df["value_duped"]

Но это далеко не правильный ответ. Я не могу придумать, как получить что-то подобное, чтобы получить желаемый результат без итерации.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
11
0
808
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Код

Если у вас не слишком много уникальных значений для id, я думаю, вы можете использовать pivot + ffill + sum.

df["desired_output"] = (
    df.pivot(columns='id', values='value').ffill().sum(axis=1).astype('int')
)

дф:

  id  value  desired_output
0  a     12              12
1  b     14              26
2  c      3              29
3  a     13              30
4  b     16              32
5  e      7              39
6  f      4              43
7  a      6              36
8  b     10              30
9  k     18              48
Ответ принят как подходящий

Пытаться:

df["out"] = (
    df.groupby("id")["value"].transform("diff").fillna(df["value"]).cumsum().astype(int)
)

print(df)

Распечатки:

  id  value  cumsum_of_value  desired_output  out
0  a     12               12              12   12
1  b     14               26              26   26
2  c      3               29              29   29
3  a     13               42              30   30
4  b     16               58              32   32
5  e      7               65              39   39
6  f      4               69              43   43
7  a      6               75              36   36
8  b     10               85              30   30
9  k     18              103              48   48

Я думаю, что это действительно хороший ответ, но у меня есть один вопрос (неважный): есть ли конкретная причина, по которой вы использовали transform?

Panda Kim 20.06.2024 02:34

@PandaKim Да, я мог бы использовать .diff(), но transform - это просто "мышечная память" :)

Andrej Kesely 20.06.2024 02:40
out = df.groupby("id")["value"].diff().fillna(0).cumsum().reset_index(drop=True)

df["out"] = out

Попробуй это.

Другие вопросы по теме