Создайте новый столбец фрейма данных pandas с помощью groupby

#pandas #dataframe #iteration #pandas-groupby #vectorization

Вопрос:

У меня есть фрейм данных, и я хотел бы сгруппировать его по значению столбца, а затем выполнить расчет для создания нового столбца. Ниже приведены настроенные данные:

 import pandas as pd

df = pd.DataFrame({
    'Red' : [1,2,3,4,5,6,7,8,9,10],
    'Groups':['A','B','A','A','B','C','B','C','B','C'],
    'Blue':[10,20,30,40,50,60,70,80,90,100]
})
   
df.groupby('Groups').apply(print)
 

Что я хочу сделать, так это создать столбец «ВСЕГО» в исходном кадре данных. Если это первая запись группы, «ИТОГО» получает ноль, в противном случае ИТОГ будет равен [«Синий»] при индексе, вычитаемом на [«Красный»] при индексе-1.

Я попытался сделать это в функции ниже, но это не работает.

 def funct(group):
    count = 0
    lst = []
    for info in group:
        if count == 0:
            lst.append(0)
            count  = 1
        else: 
            num = group.iloc[count]['Blue'] - group.iloc[count-1]['Red']
            lst.append(num)
            count  = 1
    group['Total'] = lst
    return group

df = df.join(df.groupby('Groups').apply(funct))
 

Код работает для первой группы, но затем выдает ошибки.

Желаемый результат таков:

 df_final = pd.DataFrame({
    'Red' : [1,2,3,4,5,6,7,8,9,10],
    'Groups':['A','B','A','A','B','C','B','C','B','C'],
    'Blue':[10,20,30,40,50,60,70,80,90,100],
    'Total':[0,0,29,37,48,0,65,74,83,92]
})

df_final

df_final.groupby('Groups').apply(print)
 

Спасибо вам за помощь!

Ответ №1:

Для каждой группы рассчитайте разницу между Blue и сдвинутым Red (красным цветом по предыдущему индексу):

 df['Total'] = (df.groupby('Groups')
                 .apply(lambda g: g.Blue - g.Red.shift().fillna(g.Blue))
                 .reset_index(level=0, drop=True))

df

   Red Groups  Blue  Total
0    1      A    10    0.0
1    2      B    20    0.0
2    3      A    30   29.0
3    4      A    40   37.0
4    5      B    50   48.0
5    6      C    60    0.0
6    7      B    70   65.0
7    8      C    80   74.0
8    9      B    90   83.0
9   10      C   100   92.0
 

Или, как прокомментировал @anky, вы можете избежать apply Red этого, сначала сдвинув столбец:

 df['Total'] = (df.Blue - df.Red.groupby(df.Groups).shift()).fillna(0, downcast='infer')

df
   Red Groups  Blue  Total
0    1      A    10      0
1    2      B    20      0
2    3      A    30     29
3    4      A    40     37
4    5      B    50     48
5    6      C    60      0
6    7      B    70     65
7    8      C    80     74
8    9      B    90     83
9   10      C   100     92
 

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

1. Спасибо всем вам, я собираюсь покопаться в ваших ответах!

2. к сожалению, я не смог использовать это для решения своей проблемы из-за обобщения. Очевидно, это означает, что я плохо написал вопрос, так как ответы работают.

3. В принципе, я хочу, чтобы две группы colmun применили сложную функцию, а затем обновили столбец, а затем восстановили исходный кадр данных с помощью нового столбца.

4. Проблема с использованием лямбды в том, что я не могу получить две отдельные строки для выполнения функции.

5. к сожалению, вопрос, как я его задал, очень прост и оставляет открытым вычитание.