Был бы очень признателен за помощь в этом
Для следующего набора данных:
StartDate EndDate Days 0 2018-03-20 00:36:00 2018-05-01 00:42:00 42.004167 1 2018-05-01 00:42:00 2018-06-04 17:15:38 34.690023 2 2018-04-07 15:06:00 2018-05-09 17:01:00 32.079861 3 2018-03-21 04:36:00 2018-05-14 04:00:00 53.975000 4 2018-03-15 15:30:00 2018-05-08 08:30:00 53.708333 5 2018-05-08 08:30:00 2018-06-09 10:40:09 32.090382 6 2018-03-21 09:00:00 2018-05-16 13:40:00 56.194444 7 2018-03-31 06:00:00 2018-05-26 16:30:00 56.437500 8 2018-03-14 18:18:00 2018-04-27 01:00:00 43.279167 9 2018-04-07 15:00:00 2018-06-01 09:25:50 54.767940 10 2018-03-22 07:30:00 2018-05-20 19:00:00 59.479167
Мне удалось найти разницу между датами начала и окончания и создать новый столбец «Дни» следующим образом:
df['StartDate'] = pd.to_datetime(df['StartDate'])
df['EndDate'] = pd.to_datetime(df['EndDate'])
df['Days'] = df['EndDate'].sub(df['StartDate'], axis=0)
df['Days'] = df['Days'] / np.timedelta64(1, 'D')
Однако мне нужно это выяснить:
Для каждой строки сколько дней было в каждом месяце и в каком именно месяце они были.
Я думаю, что лучше всего было бы создать столбцы для всех возможных месяцев и таким образом привязать дни к соответствующим столбцам. Но у меня опыт работы с Excel, и, вероятно, есть более разумный способ сделать это.
Причина в том, что; правильно платить клиентам в соответствии с количеством отработанных дней между датой начала и датой окончания, а также распределять их расходы на этой основе. Полный набор данных довольно велик, поэтому скрипту придется эффективно обрабатывать широкий диапазон отклонений дат.
Черная мамба






Давай попробуем это.
Сначала создайте серию дней, используя pd.date_range с StartDate и EndDate для каждой записи. Затем используйте средство доступа dt datetime, чтобы получить месяц. Используйте value_counts для подсчета общего количества месяцев для каждой записи. Наконец, присоедините результаты к исходному фрейму данных. Кроме того, import calendar для получения названия месяца по сравнению с номером, используя rename со словарем, созданным из calendar.month_names.
import calendar
df.join(df.apply(lambda x:
pd.Series(pd.date_range(x.StartDate,
x.EndDate,
freq='D')).dt.month,1)
.apply(lambda x:
x.value_counts(),1)
.rename(columns=dict(enumerate(calendar.month_name))))
Выход:
StartDate EndDate Days March April May June
0 2018-03-20 00:36:00 2018-05-01 00:42:00 42.004167 12.0 30.0 1.0 NaN
1 2018-05-01 00:42:00 2018-06-04 17:15:38 34.690023 NaN NaN 31.0 4.0
2 2018-04-07 15:06:00 2018-05-09 17:01:00 32.079861 NaN 24.0 9.0 NaN
3 2018-03-21 04:36:00 2018-05-14 04:00:00 53.975000 11.0 30.0 13.0 NaN
4 2018-03-15 15:30:00 2018-05-08 08:30:00 53.708333 17.0 30.0 7.0 NaN
5 2018-05-08 08:30:00 2018-06-09 10:40:09 32.090382 NaN NaN 24.0 9.0
6 2018-03-21 09:00:00 2018-05-16 13:40:00 56.194444 11.0 30.0 16.0 NaN
7 2018-03-31 06:00:00 2018-05-26 16:30:00 56.437500 1.0 30.0 26.0 NaN
8 2018-03-14 18:18:00 2018-04-27 01:00:00 43.279167 18.0 26.0 NaN NaN
9 2018-04-07 15:00:00 2018-06-01 09:25:50 54.767940 NaN 24.0 31.0 NaN
10 2018-03-22 07:30:00 2018-05-20 19:00:00 59.479167 10.0 30.0 20.0 NaN
Я смог отфильтровать это до моего требования показывать месяц и год, изменив dt.month на dt.strftime
df.join(df.apply(lambda x:
pd.Series(pd.date_range(x.StartDate,
x.EndDate,
freq='D')).dt.strftime('%b-%y'),1)
.apply(lambda x:
x.value_counts(),1)
.rename(columns=dict(enumerate(calendar.month_abbr))))
Однако теперь в выходных данных столбцы перечислены в алфавитном порядке, а не с января по декабрь по году.
Любые идеи о том, как этого добиться, приветствуются.
Во-первых, ваше указанное выше утверждение, вам не нужна часть переименования, потому что вы уже выполняете переименование при преобразовании в% m из ряда дат.
Теперь проблема возникает с этим методом, когда вы извлекаете .dt.month, который возвращает «номер месяца», который используется для сортировки. Когда вы меняете это название месяца, вы выполняете лексикографическую сортировку. Итак, давайте вернемся к номеру месяца (для сортировки) и выполним небольшую лямбда-функцию, чтобы преобразовать столбцы из номера месяца в имя.
df.join(df.apply(lambda x:
pd.Series(pd.date_range(x.StartDate,
x.EndDate,
freq='D')).dt.strftime('%m-%y'),1)
.apply(lambda x:
x.value_counts(),1)
.rename(columns=lambda x:
pd.to_datetime(x, format='%m-%y').strftime('%b-%y')))
Выход:
StartDate EndDate Days Mar-18 Apr-18 May-18 Jun-18
0 2018-03-20 00:36:00 2018-05-01 00:42:00 42.004167 12.0 30.0 1.0 NaN
1 2018-05-01 00:42:00 2018-06-04 17:15:38 34.690023 NaN NaN 31.0 4.0
2 2018-04-07 15:06:00 2018-05-09 17:01:00 32.079861 NaN 24.0 9.0 NaN
3 2018-03-21 04:36:00 2018-05-14 04:00:00 53.975000 11.0 30.0 13.0 NaN
4 2018-03-15 15:30:00 2018-05-08 08:30:00 53.708333 17.0 30.0 7.0 NaN
5 2018-05-08 08:30:00 2018-06-09 10:40:09 32.090382 NaN NaN 24.0 9.0
6 2018-03-21 09:00:00 2018-05-16 13:40:00 56.194444 11.0 30.0 16.0 NaN
7 2018-03-31 06:00:00 2018-05-26 16:30:00 56.437500 1.0 30.0 26.0 NaN
8 2018-03-14 18:18:00 2018-04-27 01:00:00 43.279167 18.0 26.0 NaN NaN
9 2018-04-07 15:00:00 2018-06-01 09:25:50 54.767940 NaN 24.0 31.0 NaN
10 2018-03-22 07:30:00 2018-05-20 19:00:00 59.479167 10.0 30.0 20.0 NaN
Можете ли вы предоставить ожидаемый результат?