Python For Loop для сгруппированных данных с интервалами и определенной функцией

avatar
Busiyou
9 августа 2021 в 02:24
81
1
0

Я пытаюсь рассчитать столбец индикатора, чтобы он возвращал значение 1, ЕСЛИ данный клиент возвращается за другой услугой в течение 60 дней с даты окончания данной услуги. Ниже приведена таблица данных и нужный столбец индикатора.

enter image description here

Я отсортировал и сгруппировал данные по клиентам и услугам. Теперь я пытаюсь составить формулу, которая смотрит на дату окончания каждой строки и проверяет, находятся ли какие-либо будущие даты начала обслуживания для данного клиента (группы) в пределах 60-дневного периода.

До сих пор я сгруппировал данные и попытался применить цикл for... но я продолжаю получать ошибки. Я новичок в Python, поэтому я не совсем уверен, как настроить код и синтаксис, чтобы заставить это работать. Мы будем очень признательны за любую помощь - спасибо!

df = pd.DataFrame({'Customer':['John','John','Deb','Sara','Sara','Sara','Sara','Sara','Mike','Mike','Mike'],
               'Service':['A','B','C','A','B','C','D','E','E','F','G'],
               'Start':['1/2/2020','3/1/2020','2/5/2020','2/6/2020','3/6/2020','8/2/2020','9/15/2020','10/2/2020','5/4/2020','6/8/2020','7/1/2020'],
               'End':['1/3/2020','3/11/2020','2/7/2020','2/9/2020','3/9/2020','8/12/2020','9/19/2020','10/12/2020','5/8/2020','6/18/2020','7/8/2020']})


df['Start'] = pd.to_datetime(df['Start'], infer_datetime_format=True, errors='coerce')
df['End'] = pd.to_datetime(df['End'], infer_datetime_format=True, errors='coerce')
df.dtypes

grp=df.groupby(['Customer','Service'])
grp.head(15)

def serv_days(Start,End):
    for row in df.iterrows():
        if (row[1].Start == row.End):
            continue
        if ((row[1].Start-row.End).days < 60):
            return 1
        else:
            return 0

for grpnm,each_grp in grp:
    for row in each_grp.iterrows():
        print(serv_days(each_grp,row[1].Start,row.loc('End')))
Источник

Ответы (1)

avatar
nay
9 августа 2021 в 03:03
0

как вы упомянули, мы можем просто сравнить текущую строку со следующей строкой, чтобы увидеть, равен ли клиент текущей строки клиенту следующей строки, и разница между датой окончания текущей строки и датой начала следующей строки меньше 60 дней.
следуйте за умом,нам не нужен groupby,нам нужен:

  • сдвинуть фрейм данных с помощью df[1:], что означает удалить первую строку и сохранить другие строки
  • нам нужно reset_index, чтобы объединить index с исходным df, поэтому теперь у нас есть кадр данных, объединяющий текущую строку и следующую строку в одной строке
  • просто сравните customer и customer_next(суффикс _next добавляется параметром merge функции suffixes) и diff <62249597022408>
df = pd.DataFrame({'Customer':['John','John','Deb','Sara','Sara','Sara','Sara','Sara','Mike','Mike','Mike'],
               'Service':['A','B','C','A','B','C','D','E','E','F','G'],
               'Start':['1/2/2020','3/1/2020','2/5/2020','2/6/2020','3/6/2020','8/2/2020','9/15/2020','10/2/2020','5/4/2020','6/8/2020','7/1/2020'],
               'End':['1/3/2020','3/11/2020','2/7/2020','2/9/2020','3/9/2020','8/12/2020','9/19/2020','10/12/2020','5/8/2020','6/18/2020','7/8/2020']})

df['Start'] = pd.to_datetime(df['Start'], infer_datetime_format=True, errors='coerce')
df['End'] = pd.to_datetime(df['End'], infer_datetime_format=True, errors='coerce')

new_df = pd.merge(df,df[1:].reset_index(drop=True),suffixes=['','_next'],left_index=True,right_index=True,how='left')
new_df['indicator'] = (new_df['Customer'] == new_df['Customer_next']) & ((new_df['Start_next']-new_df['End'])<pd.Timedelta('60 days'))
new_df = new_df[['Customer','Service','Start','End','indicator']]
    Customer    Service   Start         End         indicator
0   John        A         2020-01-02    2020-01-03  TRUE
1   John        B         2020-03-01    2020-03-11  FALSE
2   Deb         C         2020-02-05    2020-02-07  FALSE
3   Sara        A         2020-02-06    2020-02-09  TRUE
4   Sara        B         2020-03-06    2020-03-09  FALSE
5   Sara        C         2020-08-02    2020-08-12  TRUE
6   Sara        D         2020-09-15    2020-09-19  TRUE
7   Sara        E         2020-10-02    2020-10-12  FALSE
8   Mike        E         2020-05-04    2020-05-08  TRUE
9   Mike        F         2020-06-08    2020-06-18  TRUE
10  Mike        G         2020-07-01    2020-07-08  FALSE
Busiyou
9 августа 2021 в 15:36
0

Спасибо за исправления @nay, я исправил даты окончания и добавил примерную таблицу результатов, которые я надеялся получить. Код, который вы предоставили, очень помогает, но возвращает все 1... Я думаю, что он сравнивает только даты начала и окончания текущей строки? Например, когда мы смотрим на клиента Сару, я надеялся сравнить дату окончания услуги А с датами начала всех будущих услуг, чтобы проверить, не наступили ли они в пределах 60 дней. Затем то же самое для следующего ряда. Мне нужно сравнить дату окончания услуги B для Сары со всеми будущими датами начала, чтобы узнать, оказывались ли ей дополнительные услуги в течение 60 дней и т. д.