Более логичное решение c Pandas, вместо того, чтобы вручную циклически проходить по каждой строке, состоит в том, чтобы получить диапазон дат, который вы хотите для каждой строки, а затем транспонировать (используя explode
), чтобы получить по одной строке на дату:
import pandas as pd
import numpy as np
from datetime import timedelta
# Set up input data (taken from original post)
df = pd.DataFrame({
'date': ['2019-01-01','2019-01-02','2019-01-03', '2019-01-04',
'2019-05-20','2019-05-21','2019-05-22', '2019-05-23',
'2019-03-01','2019-03-02','2019-03-03', '2019-03-04'],
'new_start_date': ['2020-03-01','2020-03-01','2020-03-01', '2020-03-01',
'2020-02-25','2020-02-25','2020-02-25', '2020-02-25',
'2020-01-19','2020-01-19','2020-01-19', '2020-01-19'],
'category': ['Category A']*4 + ['Category B']*4 + ['Category C']*4
})
df['date'] = pd.to_datetime(df['date'], format="%Y/%m/%d").dt.date
df['new_start_date'] = pd.to_datetime(df['new_start_date'], format="%Y/%m/%d").dt.date
################
# SOLUTION BELOW
################
# Convert DF to one row per category, with desired start and end dates
new_df = df[['category', 'new_start_date']].drop_duplicates().reset_index(drop=True)
new_df['extra_days'] = df.groupby('category')['date'].count().reset_index(drop=True) - 1
new_df['end_date'] = new_df.apply(lambda row: row.new_start_date + pd.Timedelta(f'{row.extra_days} days'), axis=1)
# Create list of days between start- and end-date, then transpose(explode) to get one row per date
new_df['dates'] = new_df.apply(lambda row: pd.date_range(row.new_start_date, row.end_date, freq='D'), axis=1)
final_df = new_df.explode('dates').loc[:, ['category', 'new_start_date', 'dates']].rename(columns={'dates':'new_date'})
ВЫХОД:
>>> final_df
>>> final_df
category new_start_date new_date
0 Category A 2020-03-01 2020-03-01
0 Category A 2020-03-01 2020-03-02
0 Category A 2020-03-01 2020-03-03
0 Category A 2020-03-01 2020-03-04
1 Category B 2020-02-25 2020-02-25
1 Category B 2020-02-25 2020-02-26
1 Category B 2020-02-25 2020-02-27
1 Category B 2020-02-25 2020-02-28
2 Category C 2020-01-19 2020-01-19
2 Category C 2020-01-19 2020-01-20
2 Category C 2020-01-19 2020-01-21
2 Category C 2020-01-19 2020-01-22