Объединение значений из более ранних строк с разными датами в кадре данных pandas - PullRequest
3 голосов
/ 19 сентября 2019

Расширение моего предыдущего вопроса .У меня есть исходный фрейм данных, который имеет три столбца: Customer, Date и Item.Я хочу добавить новый столбец, содержащий историю элементов, представляющий собой массив всех элементов для этого клиента, которые находятся в более ранних (определяемых датой) строках. Если клиент совершил несколько покупок в одну и ту же дату, ни один элемент строки не должен быть указан в истории элементов для другого.

Итак, учитывая данные этого примера:

df = pd.DataFrame({'Customer':['Bert', 'Bert', 'Bert', 'Bert', 'Bert', 'Ernie', 'Ernie', 'Ernie', 'Ernie', 'Steven', 'Steven'], 'Date':['01/01/2019', '15/01/2019', '20/01/2019', '20/01/2019', '22/01/2019', '01/01/2019', '15/01/2019', '20/01/2019', '22/01/2019', '01/01/2019' ,'15/01/2019'], 'Item':['Bread', 'Cheese', 'Apples', 'Pears', 'Toothbrush', 'Toys', 'Shellfish', 'Dog', 'Yoghurt', 'Toilet', 'Dominos']})
Customer    Date    Item
Bert    01/01/2019  Bread
Bert    15/01/2019  Cheese
Bert    20/01/2019  Apples
Bert    20/01/2019  Pears
Bert    22/01/2019  Toothbrush
Ernie   01/01/2019  Toys
Ernie   15/01/2019  Shellfish
Ernie   20/01/2019  Dog
Ernie   22/01/2019  Yoghurt
Steven  01/01/2019  Toilet
Steven  15/01/2019  Dominos

Вывод, который я хотел бы видеть, будет таким:

Customer    Date    Item        Item History
Bert    01/01/2019  Bread       NaN
Bert    15/01/2019  Cheese      [Bread]
Bert    20/01/2019  Apples      [Bread, Cheese]
Bert    20/01/2019  Pears       [Bread, Cheese]
Bert    22/01/2019  Toothbrush  [Bread, Cheese, Apples, Pears]
Ernie   01/01/2019  Toys        NaN
Ernie   15/01/2019  Shellfish   [Toys]
Ernie   20/01/2019  Dog         [Toys, Shellfish]
Ernie   22/01/2019  Yoghurt     [Toys, Shellfish, Dog]
Steven  01/01/2019  Toilet      NaN
Steven  15/01/2019  Dominos     [Toilet]

Обратите внимание, что для покупок Берта 20/01/2019 ни один столбец «История» не содержит предмет другого.Для его покупки 22/01/2019 включены оба предмета от 20/01/2019.

Ответ на предыдущий вопрос - отличный бит понимания списка в форме:

df['Item History'] = [x.Item[:i].tolist() for j, x in df.groupby('Customer') 
                                          for i in range(len(x))]

df.loc[~df['Item History'].astype(bool), 'Item History']= np.nan

Но, очевидно, «i» в x.Item[:i] должно работать в последней строкегде Дата не совпадает с текущей строкой.Любой совет по достижению этого очень ценится.

Ответы [ 3 ]

2 голосов
/ 19 сентября 2019

Идея состоит в том, чтобы различать дублированные значения по группам на DataFrame.duplicated, а затем заменить значения на NaN s с пропуском пропущенных значений вперед.

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

df['Item History'] = [x.Item[:i].tolist() for j, x in df.groupby('Customer') 
                                          for i in range(len(x))]

df['Item History'] = df['Item History'].mask(df.duplicated(['Customer','Date'])).ffill()

df.loc[~df['Item History'].astype(bool), 'Item History']= np.nan
print (df)
   Customer        Date        Item                    Item History
0      Bert  01/01/2019       Bread                             NaN
1      Bert  15/01/2019      Cheese                         [Bread]
2      Bert  20/01/2019      Apples                 [Bread, Cheese]
3      Bert  20/01/2019       Pears                 [Bread, Cheese]
4      Bert  22/01/2019  Toothbrush  [Bread, Cheese, Apples, Pears]
5     Ernie  01/01/2019        Toys                             NaN
6     Ernie  15/01/2019   Shellfish                          [Toys]
7     Ernie  20/01/2019         Dog               [Toys, Shellfish]
8     Ernie  22/01/2019     Yoghurt          [Toys, Shellfish, Dog]
9    Steven  01/01/2019      Toilet                             NaN
10   Steven  15/01/2019     Dominos                        [Toilet]
2 голосов
/ 19 сентября 2019

Другой способ с apply и np.cumsum():

#aggregates Item as list per 'Customer'& 'Date'
m=df.groupby(['Customer','Date'])['Item'].apply(lambda x: 
                               [*itertools.chain.from_iterable([x])])
#groups each Customer and cumsum the list with shift
n=m.groupby(level=0).apply(lambda x:np.cumsum(x).shift())
df.set_index(['Customer','Date']).assign(Item=n).reset_index() #assign back

   Customer        Date                            Item
0      Bert  01/01/2019                             NaN
1      Bert  15/01/2019                         [Bread]
2      Bert  20/01/2019                 [Bread, Cheese]
3      Bert  20/01/2019                 [Bread, Cheese]
4      Bert  22/01/2019  [Bread, Cheese, Apples, Pears]
5     Ernie  01/01/2019                             NaN
6     Ernie  15/01/2019                          [Toys]
7     Ernie  20/01/2019               [Toys, Shellfish]
8     Ernie  22/01/2019          [Toys, Shellfish, Dog]
9    Steven  01/01/2019                             NaN
10   Steven  15/01/2019                        [Toilet]
1 голос
/ 19 сентября 2019

Возможно, более простой ответ с использованием apply - это может быть медленнее, чем другие методы:

df['item history'] = df.apply(lambda x: 
            [i for i in list(df.loc[(df.Date<x.Date)&(df.Customer==x.Customer),'Item'])], axis=1)

result:

   Customer               ...                                  item history
0      Bert               ...                                            []
1      Bert               ...                                       [Bread]
2      Bert               ...                               [Bread, Cheese]
3      Bert               ...                               [Bread, Cheese]
4      Bert               ...                [Bread, Cheese, Apples, Pears]
5     Ernie               ...                                            []
6     Ernie               ...                                        [Toys]
7     Ernie               ...                             [Toys, Shellfish]
8     Ernie               ...                        [Toys, Shellfish, Dog]
9    Steven               ...                                            []
10   Steven               ...                                      [Toilet]

Возможно, вы захотите добавить list(set()) к результатуесли вы хотите список уникальных предметов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...