#python #pandas
#python #pandas
Вопрос:
У меня есть следующий фрейм данных Pandas, который состоит из столбца Member и SaleDate. Я создал дополнительный столбец для представления начала месяца для каждой строки.
a = pd.DataFrame({'Member':['A','A','A','A','A','A','B','B','B','B','B'],
'SaleDate': ['2020-01-01','2020-02-01','2020-02-29','2020-02-14','2020-03-31','2020-04-30','2020-02-29','2020-03-31','2020-04-30','2020-05-30','2020-06-14']})
a['SaleDate'] = a['SaleDate'].apply(pd.to_datetime)
a['Date_Month_Start'] = a['SaleDate'].values.astype('datetime64[M]')
Я использовал следующее, чтобы найти следующую дату транзакции для каждого участника, которая работает нормально.
a['last_tx'] = a.sort_values(by=['SaleDate'], ascending= True).groupby(['Member'])['SaleDate'].shift(1)
a['next_tx'] = a.sort_values(by=['SaleDate'], ascending= True).groupby(['Member'])['SaleDate'].shift(-1)
Теперь я хочу, чтобы для каждой строки находили последний и следующий месяц транзакции, но
a['last_month_tx'] = a.sort_values(by=['Date_Month_Start'], ascending= True).groupby(['Member'])['Date_Month_Start'].shift(1)
a['next_month_tx'] = a.sort_values(by=['Date_Month_Start'], ascending= True).groupby(['Member'])['Date_Month_Start'].shift(-1)
не удаляет дубликаты значений в столбце Date_Month_Start .
Я использовал следующее для решения проблемы, но мне было интересно, есть ли более элегантное решение этой проблемы без создания дополнительного фрейма данных и объединения его обратно.
a_month = a[['Member','Date_Month_Start']].drop_duplicates()
a_month['last_month_tx'] = a.sort_values(by=['Date_Month_Start'], ascending= True).groupby(['Member'])['Date_Month_Start'].shift(1)
a_month['next_month_tx'] = a.sort_values(by=['Date_Month_Start'], ascending= True).groupby(['Member'])['Date_Month_Start'].shift(-1)
result = pd.merge(a,a_month,how = 'left', left_on=['Member','Date_Month_Start'], right_on =['Member','Date_Month_Start'])
Ответ №1:
Я думаю, что то, как вы это сделали, достаточно элегантно. Я не смог найти способ не использовать drop_duplicates
, но мы можем использовать его внутри groupby
функции (поэтому вам не нужно создавать новую переменную с фреймом данных).
# First, sort the date values per group at once
a = a.groupby('Member').apply(lambda x: x.sort_values(['Date_Month_Start','SaleDate'])).reset_index(drop=True)
# Then, perform the calculations by Member:
a[['last_tx','next_tx','last_month_tx','next_month_tx']] = (
a.groupby('Member')
.apply(lambda x: pd.DataFrame({
'last_tx' : x['SaleDate'].shift(),
'next_tx' : x['SaleDate'].shift(-1),
'last_month_tx' : x['Date_Month_Start'].drop_duplicates().shift().reindex(x.index).ffill(),
'next_month_tx' : x['Date_Month_Start'].drop_duplicates().shift(-1).reindex(x.index[:-1]).ffill().reindex(x.index)
})
))
Вывод:
Member SaleDate Date_Month_Start last_tx next_tx last_month_tx next_month_tx
0 A 2020-01-01 2020-01-01 NaT 2020-02-01 NaT 2020-02-01
1 A 2020-02-01 2020-02-01 2020-01-01 2020-02-29 2020-01-01 2020-03-01
2 A 2020-02-29 2020-02-01 2020-02-01 2020-02-14 2020-01-01 2020-03-01
3 A 2020-02-14 2020-02-01 2020-02-29 2020-03-31 2020-01-01 2020-03-01
4 A 2020-03-31 2020-03-01 2020-02-14 2020-04-30 2020-02-01 2020-04-01
5 A 2020-04-30 2020-04-01 2020-03-31 NaT 2020-03-01 NaT
6 B 2020-02-29 2020-02-01 NaT 2020-03-31 NaT 2020-03-01
7 B 2020-03-31 2020-03-01 2020-02-29 2020-04-30 2020-02-01 2020-04-01
8 B 2020-04-30 2020-04-01 2020-03-31 2020-05-30 2020-03-01 2020-05-01
9 B 2020-05-30 2020-05-01 2020-04-30 2020-06-14 2020-04-01 2020-06-01
10 B 2020-06-14 2020-06-01 2020-05-30 NaT 2020-05-01 NaT
Здесь я использовал reindex
для воссоздания потерянных индексов sort_values
, а затем заполнял NaN
их соответствующим образом. Поскольку мы не можем заполнить все NaN
для следующей даты, используя прямое заполнение (потому что у последней даты нет следующей даты), я переиндексировал ее дважды (в первый раз я исключаю последнюю строку группы).