Pandas. Разбить период посуточно с учетом времени

Рейтинг: 0Ответов: 3Опубликовано: 30.03.2023

Всем добрый день!

Есть датафрейм со столбцами даты начала и даты окончания.

введите сюда описание изображения

Хочется получить строку для каждого дня из этого диапазона, как в примере ниже: введите сюда описание изображения

Бывает такое, что datefrom и datetill в рамках одного дня будут.

Код для изначального датафрейма.

df = pd.DataFrame({
    'datefrom': ['01.01.2023 13:00'],
    'datetill': ['01.03.2023 15:00']
}).astype({'datefrom': 'datetime64', 'datetill': 'datetime64'})

Всем откликнувшимся спасибо!

Ответы

▲ 2

Создаем фрейм с днями с помощью date_range, сбрасывая время на 0 через параметр normalize, затем копируем колонку date в datefrom. Потом создаем колонку datetill как datefrom + 1 день - 1 секунда - это и будет 59:59. В конце заменяем первое в datefrom и последнее в datetill значения на дату/время из df.

df = pd.DataFrame({
    'datefrom': ['01.01.2023 13:00'],
    'datetill': ['01.03.2023 15:00']
}).astype({'datefrom': 'datetime64', 'datetill': 'datetime64'})

dfrom, dtill = df.at[0, 'datefrom'], df.at[0, 'datetill']
df1 = pd.DataFrame({'date': pd.date_range(dfrom, dtill, freq='D', normalize=True)}).assign(datefrom=lambda x: x['date'])
df1['datetill'] = df1.datefrom + pd.Timedelta(1, unit='d') - pd.Timedelta(1, unit='s')
df1.at[df1.iloc[0].name, 'datefrom'], df1.at[df1.iloc[-1].name, 'datetill'] = dfrom, dtill

print(df)
print(df1)
             datefrom            datetill
0 2023-01-01 13:00:00 2023-01-03 15:00:00
        date            datefrom            datetill
0 2023-01-01 2023-01-01 13:00:00 2023-01-01 23:59:59
1 2023-01-02 2023-01-02 00:00:00 2023-01-02 23:59:59
2 2023-01-03 2023-01-03 00:00:00 2023-01-03 15:00:00
▲ 1

я в общем-то использовал похожий инструментарий, что и @Алексей Р:

df["ranges"] = df.apply(lambda x: pd.date_range(start=x["datefrom"], end=x["datetill"], freq="D", normalize=True), axis=1)
df = df.explode("ranges")

df.loc[df["datefrom"].dt.date != df["ranges"],"datefrom"] = df.loc[df["datefrom"].dt.date != df["ranges"],"ranges"]
df.loc[df["datetill"].dt.date != df["ranges"],"datetill"] = df.loc[df["datetill"].dt.date != df["ranges"],"ranges"]+pd.Timedelta(hours=23, minutes=59)

df:

             datefrom            datetill     ranges
0 2023-01-01 13:00:00 2023-01-01 23:59:00 2023-01-01
0 2023-01-02 00:00:00 2023-01-02 23:59:00 2023-01-02
0 2023-01-03 00:00:00 2023-01-03 15:00:00 2023-01-03
1 2023-01-04 13:00:00 2023-01-04 18:00:00 2023-01-04
▲ 0

Друзья, спасибо! Разберу все варианты предложенные :-)

Выложу как я решил, нубский вариант:

df['date']=[pd.date_range(x , y , normalize=True ) for x , y in zip(df.datefrom, df.datetill)]
df=df.explode('date')
df = df.loc[:, ['date', 'datefrom', 'datetill']]
df = df.dropna(subset=['date'])
df['date_2'] =df[['date', 'datefrom']].max(axis=1)
df['date_3'] = pd.to_datetime(df.date.astype(str) + ' ' + str(time(23,59,59)))
df['date_4'] = df[['date_3', 'datetill']].min(axis=1)
df = df[['date', 'date_2', 'date_4']]
df = df.rename(columns={'date_2': 'datefrom', 'date_4': 'datetill'})