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

#python #pandas #datetime

#python #pandas #дата и время

Вопрос:

У меня есть фрейм данных, который выглядит примерно так (за исключением того, что количество Visit Deliv столбцов и увеличивается до Visit_84 и Deliv 84 и есть несколько сотен клиентов — я упростил его здесь)

 Client   Visit_1    Visit_2    Visit_3    Deliv_1  Deliv_2  Deliv_3 Key_DT
Client_1 2018-01-01 2018-01-20 2018-02-10 No       Yes      Yes     2018-01-15
Client_2 2018-01-10 2018-01-30 2018-02-10 Yes      Yes      No      2018-01-25
Client_3 2018-01-20 2018-04-01 2018-04-10 Yes      Yes      Yes     2018-04-15
Client_4 2018-01-30 2018-03-01 2018-03-10 Yes      No       Yes     2018-02-25
 

Я хочу создать новый столбец с именем Vis_sum , который показывает сумму количества посещений от Visit_1 до Visit_3 , которые следуют за Key_DT в той же строке и имеют a Yes в соответствующем Deliv столбце (например Deliv_1 , связано с Visit_1 ). Это должно выглядеть так

 Client   Visit_1    Visit_2    Visit_3    Deliv_1  Deliv_2  Deliv_3 Key_DT     Vis_sum
Client_1 2018-01-01 2018-01-20 2018-02-10 No       Yes      Yes     2018-01-15 2
Client_2 2018-01-10 2018-01-30 2018-02-10 Yes      Yes      No      2018-01-25 1
Client_3 2018-01-20 2018-04-01 2018-04-10 Yes      Yes      Yes     2018-04-15 0
Client_4 2018-01-30 2018-03-01 2018-03-10 Yes      No       Yes     2018-02-25 1
 

Ответ №1:

Это предполагает, что все ваши столбцы datetime . Если это не так, преобразуйте их.


Настройка

 a = df.filter(like='Visit').values
b = df.filter(like='Deliv').eq('Yes').values
c = df['Key_DT'].values
 

Использование сравнения с широковещательной передачей

 ((a > c[:, None]) amp; b).sum(1)
 
 array([2, 1, 0, 1])
 

 df.assign(Vis_sum=((a > c[:, None]) amp; b).sum(1))
 
      Client    Visit_1    Visit_2    Visit_3 Deliv_1 Deliv_2 Deliv_3     Key_DT  Vis_sum
0  Client_1 2018-01-01 2018-01-20 2018-02-10      No     Yes     Yes 2018-01-15        2
1  Client_2 2018-01-10 2018-01-30 2018-02-10     Yes     Yes      No 2018-01-25        1
2  Client_3 2018-01-20 2018-04-01 2018-04-10     Yes     Yes     Yes 2018-04-15        0
3  Client_4 2018-01-30 2018-03-01 2018-03-10     Yes      No     Yes 2018-02-25        1
 

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

1. Спасибо за вашу помощь. Я немного изменил его, так как мне также нужно выполнять задачу только на клиентах, где ключевая дата превышает определенную дату. Теперь это выглядит так: df.loc[(df.Key_DT > '2018-02-01'), 'Vis_sum']=((a > c[:, None]) amp; b).sum(1)) . Однако ни этот пересмотренный код, ни предоставленный вами оригинал не будут работать. я получаю следующее сообщение об ошибке : operands could not be broadcast together with shapes (1537,81) (1537,12) . Проблема в том, что Visit во всех столбцах, Deliv столбцах и Key_DT столбцах отсутствуют какие-либо данные? Если да, то как мне это обойти?

2. @FGreen вам нужно применить ту же маску при создании a , b , и c которую вы делаете при индексации фрейма данных. Так что для a , это стало бы и т.д. df.filter(like='Visit').loc[df.Key_DT > '2018-02-01'] .

3.Спасибо. Итак, я внес следующие изменения: a = df.filter(like='Visit').loc[df.Key_DT > '2018-02-01'] b = df.filter(like='Deliv').eq('Yes').loc[df.Key_DT > '2018-02-01'] c = df['Key_DT'].loc[df.Key_DT > '2018-02-01'] Однако я все еще получаю аналогичное сообщение об ошибке: cannot broadcast shape [(13, 81)] with block values [(13, 1)]

4. Исправили ошибку (я использовал неправильные столбцы «посещения») — теперь они ошибка читает cannot broadcast shape [(13, 12)] with block values [(13, 1)]

Ответ №2:

Вот np подход:

 deliv_cols = [col for col in df.columns if 'Deliv' in col]
visit_cols = [col for col in df.columns if 'Visit' in col]

flags = df[deliv_cols].apply(lambda x: x.str.contains('Y'))
date_flags = df[visit_cols].apply(lambda x: x>df.Key_DT)

df['Vis_sum'] = np.sum(flags.values amp; date_flags.values,axis=1)
 

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

1. Как и выше, я получаю аналогичное сообщение об ошибке: operands could not be broadcast together with shapes (1537,12) (1537,81)

2. Проверьте len(deliv_cols) и len(visit_cols). Являются ли они оба 84, как заявлено?

3. Извинения — это не так. их 84 visit_cols , но только 12 `deliv_cols’

4. Итак, как вы связываете 84 посещения с 12 поставками? Я имею в виду, что это не может быть «visit_1 с deliv_1 и так далее», верно?

5. Игнорируйте это — они имеют одинаковую длину, извинения, 12 столбцов посещения, 12 столбцов deliv