Выбор всех записей данных за предыдущие 6 месяцев по появлению определенного значения в столбце в pandas

#pandas

#pandas

Вопрос:

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

 Cust_ID Transaction_Date Amount Description
1         08/01/2017        12       Moved
1         03/01/2017        15        X
1         01/01/2017         8        Y
2         10/01/2018         6       Moved
2         02/01/2018        12        Z
  

Здесь я хочу увидеть описание «Перемещено», а затем выбрать все последние 6 месяцев для каждого Cust_ID.

Вывод должен выглядеть следующим образом:

 Cust_ID   Transaction_Date   Amount    Description
    1         08/01/2017        12       Moved
    1         03/01/2017        15        X
    2         10/01/2018         6       Moved
  

Я хочу сделать это на python. Пожалуйста, помогите.

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

1. значит 08/01/2017 08 — это число, а 01 — месяц ryt?

2. Почему в ожидаемом наборе результатов есть строка с описанием «X» для описания «Перемещено»? Где твоя попытка?

3. Есть только один Moved для каждой группы?

4. @anky_91 да, верно

Ответ №1:

Идея создается Series из datetimes отфильтрованных Moved и сдвинутых MonthOffset значений, последний фильтр по Series.map значениям, менее подобным этому, смещает:

РЕДАКТИРОВАТЬ: получить все даты и времени для каждого Moved значения:

 df['Transaction_Date'] = pd.to_datetime(df['Transaction_Date'])
df = df.sort_values(['Cust_ID','Transaction_Date'])
df['g'] = df['Description'].iloc[::-1].eq('Moved').cumsum()

s = (df[df['Description'].eq('Moved')]
        .set_index(['Cust_ID','g'])['Transaction_Date'] - pd.offsets.MonthOffset(6))

mask = df.join(s.rename('a'), on=['Cust_ID','g'])['a'] < df['Transaction_Date']
df1 = df[mask].drop('g', axis=1)
  

ПРАВКА1: Получить все даты для Moved с минимальными датами для групп, другие Moved для групп удаляются:

 print (df)
   Cust_ID Transaction_Date  Amount Description
0        1       10/01/2017      12           X
1        1       01/23/2017      15       Moved
2        1       03/01/2017       8           Y
3        1       08/08/2017      12       Moved
4        2       10/01/2018       6       Moved
5        2       02/01/2018      12           Z

#convert to datetimes
df['Transaction_Date'] = pd.to_datetime(df['Transaction_Date'])

#mask for filter Moved rows
mask = df['Description'].eq('Moved')
#filter and sorting this rows
df1 = df[mask].sort_values(['Cust_ID','Transaction_Date'])
print (df1)
   Cust_ID Transaction_Date  Amount Description
1        1       2017-01-23      15       Moved
3        1       2017-08-08      12       Moved
4        2       2018-10-01       6       Moved
  

 #get duplicated filtered rows in df1
mask = df1.duplicated('Cust_ID')
#create Series for map
s = df1[~mask].set_index('Cust_ID')['Transaction_Date'] - pd.offsets.MonthOffset(6)
print (s)
Cust_ID
1   2016-07-23
2   2018-04-01
Name: Transaction_Date, dtype: datetime64[ns]

#create mask for filter out another Moved (get only first for each group)
m2 = ~mask.reindex(df.index, fill_value=False)
df1 = df[(df['Cust_ID'].map(s) < df['Transaction_Date']) amp; m2]
print (df1)
   Cust_ID Transaction_Date  Amount Description
0        1       2017-10-01      12           X
1        1       2017-01-23      15       Moved
2        1       2017-03-01       8           Y
4        2       2018-10-01       6       Moved
  

ПРАВКА2:

 #get last duplicated filtered rows in df1
mask = df1.duplicated('Cust_ID', keep='last')
#create Series for map
s = df1[~mask].set_index('Cust_ID')['Transaction_Date'] 
print (s)
Cust_ID
1   2017-08-08
2   2018-10-01
Name: Transaction_Date, dtype: datetime64[ns]

m2 = ~mask.reindex(df.index, fill_value=False)
#filter by between Moved and next 6 months
df3 = df[df['Transaction_Date'].between(df['Cust_ID'].map(s), df['Cust_ID'].map(s   pd.offsets.MonthOffset(6))) amp; m2]
print (df3)
   Cust_ID Transaction_Date  Amount Description
3        1       2017-08-08      12       Moved
0        1       2017-10-01      12           X
4        2       2018-10-01       6       Moved
  

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

1. Это хороший вариант, но в некоторых случаях он завершится неудачей, если у нас будет несколько Moved событий. Я обновил свой пример на случай, когда этот подход не работает (см. Обновление). В моем примере с вашим кодом мы бы отобразили 2017-03-01 событие, хотя оно не предшествует ни одной Moved записи с окном за 6 месяцев (следующим Moved является 2017-10-01 )

2. @perl — я, это зависит от того, что нужно op. К сожалению, фильтрация по группам возможна, но медленная…

3. Я думаю, что нашел быстрый способ (мне нужно только bfill сгруппировать данные) и правильно обрабатывает эти случаи. Обновил мой ответ этим

4. @jezrael Привет, 1 последний question…in приведенный выше сценарий, если мне нужно извлечь данные за 6 месяцев… что все, что мне нужно сделать в коде «РЕДАКТИРОВАТЬ». Заранее спасибо.

5. @AnkitaPatnaik — Я думаю, нужно изменить только - pd.offsets.MonthOffset(6) на pd.offsets.MonthOffset(6)