Добавить в эту строку значение последней строки - PullRequest
1 голос
/ 09 мая 2020

Я хочу получить значение последней строки при группировке по имени. Например, последняя итерация имени Уолтер в строке 2, я хочу получить Dog + "," + Cat для Col1 и Beer + "," + Wine в Col3. Столбцов много, поэтому я хотел бы сделать это на основе индексации / позиции столбца, а не имен столбцов.

+------+---------+-------+
| Col1 |  Name   | Col3  |
+------+---------+-------+
| Dog  | Walter  | Beer  |
| Cat  | Walter  | Wine  |
| Dog  | Alfonso | Cider |
| Dog  | Alfonso | Cider |
| Dog  | Alfonso | Vodka |
+------+---------+-------+

Это результат, который я хочу:

+---------------+---------------------------+---------------------+
|     Col1      |           Name            |        Col3         |
+---------------+---------------------------+---------------------+
| Dog           | Walter                    | Beer                |
| Dog, Cat      | Walter, Walter            | Beer, Wine          |
| Dog           | Alfonso                   | Cider               |
| Dog, Dog      | Alfonso, Alfonso          | Cider, Cider        |
| Dog, Dog, Dog | Alfonso, Alfonso, Alfosno | Cider, Cider, Vodka |
+---------------+---------------------------+---------------------+

Это то, что я пробовал (но не работает):

for i in df:
    if df.loc[i,1] == df.loc[i+1,1]:
        df.loc[i,0] + ", " + df.loc[i+1,0]
    else:
        df.loc[i+1,0]

Я читал, что итерация по строкам в pandas с for-l oop не одобряется, поэтому я хотел бы получить вывод с помощью векторизации или применения (или другого эффективного способа).

Ответы [ 4 ]

3 голосов
/ 09 мая 2020

То, что вы в основном пытаетесь сделать, - это запустить функцию коммутативного агрегирования для каждой группы. Pandas имеет comsum для обычного добавления, но не поддерживает настраиваемые коммутативные функции. Для этого вы можете использовать некоторые numpy функции:

df = pd.DataFrame({"col1": ["D", "C", "D", "D", "D"], "Name": ["W", "W", "A", "A", "A"], 
                   "col3": ["B", "W", "C", "C", "V"] })


import numpy as np
def ser_accum(op,ser):
    u_op = np.frompyfunc(op, 2, 1) # two inputs, one output
    return u_op.accumulate(ser, dtype=np.object)

def plus(x,y):
    return x + "," + y

def accum(df):
    for col in df.columns:
        df[col] = ser_accum(plus, df[col])
    return df

df.groupby("Name").apply(accum)

Вот результат:

col1    Name    col3
0   D   W   B
1   D,C W,W B,W
2   D   A   C
3   D,D A,A C,C
4   D,D,D   A,A,A   C,C,V
2 голосов
/ 09 мая 2020

вот другой способ использования accumulate в индексе и использования метода df.agg:

from itertools import accumulate
import numpy as np

def fun(a):
    l = [[i] for i in a.index]
    acc = list(accumulate(l, lambda x, y: np.concatenate([x, y])))
    return pd.concat([a.loc[idx].agg(','.join) for idx in acc],axis=1).T
out = pd.concat([fun(v) for k,v in df.groupby('Name',sort=False)])

print(out)
          Col1                     Name               Col3
0          Dog                   Walter               Beer
1      Dog,Cat            Walter,Walter          Beer,Wine
0          Dog                  Alfonso              Cider
1      Dog,Dog          Alfonso,Alfonso        Cider,Cider
2  Dog,Dog,Dog  Alfonso,Alfonso,Alfonso  Cider,Cider,Vodka

Вы можете добавить индекс сброса с drop=True в конце к сбросить индексы

2 голосов
/ 09 мая 2020

можно использовать groupby и cumsum. Если вы не возражаете (в зависимости от вашего использования после) наличия дополнительной запятой / пробела в конце, вы можете сделать:

print (df.groupby('Name')[['Col1', 'Col3']].apply(lambda x: (x + ', ').cumsum()))
              Col1                   Col3
0            Dog,                  Beer, 
1       Dog, Cat,            Beer, Wine, 
2            Dog,                 Cider, 
3       Dog, Dog,          Cider, Cider, 
4  Dog, Dog, Dog,   Cider, Cider, Vodka, 

, но если вы хотите удалить лишнюю запятую / пробел, просто добавьте str [: - 2] в каждый столбец, например:

print (df.groupby('Name')[['Col1', 'Col3']].apply(lambda x: (x + ', ').cumsum())\
         .apply(lambda x: x.str[:-2]))
            Col1                 Col3
0            Dog                 Beer
1       Dog, Cat           Beer, Wine
2            Dog                Cider
3       Dog, Dog         Cider, Cider
4  Dog, Dog, Dog  Cider, Cider, Vodka
1 голос
/ 09 мая 2020

Если вас интересует только последняя строка результаты Col1 и Col3, попробуйте следующее:

df.groupby('Name').agg(', '.join)

Результат:

                  Col1                 Col3
Name                                       
Alfonso  Dog, Dog, Dog  Cider, Cider, Vodka
Walter        Dog, Cat           Beer, Wine
...