如何用Python基于起止日期列生成每日DataFrame?
将促销活动DataFrame按日期拆分为多行的高效实现方法
我有一个记录促销活动及其起止日期的DataFrame,需要将每行数据拆分为与促销天数对应的多行数据。
当前DataFrame示例
import pandas as pd sample_dict = {'start_date': ["2021-01-01", "2022-01-01", "2023-03-01"], 'end_date': ["2021-01-31", "2022-01-31", "2023-03-31"], 'promo_item_no': ["a12345", 'b12345', 'c12345'], 'cannibalized': [1,0,1]} sample_df = pd.DataFrame.from_dict(sample_dict) sample_df.loc[:, 'start_date'] = pd.to_datetime(sample_df.loc[:, 'start_date'], format = "%Y-%m-%d") sample_df.loc[:, 'end_date'] = pd.to_datetime(sample_df.loc[:, 'end_date'], format = "%Y-%m-%d")
期望结果
将每行数据按start_date到end_date的日期范围拆分为多行,每行对应一个日期,同时保留promo_item_no和cannibalized的对应值,示例结果如题目中sample_df2所示。
高效实现方法
方法一:apply + explode(中小数据量适用)
通过apply为每行生成日期序列,再用explode展开,代码简洁易读:
# 为每行生成连续日期序列 sample_df['date'] = sample_df.apply(lambda x: pd.date_range(x['start_date'], x['end_date'], freq='D'), axis=1) # 展开日期列,删除原起止日期列 result_df = sample_df.explode('date').drop(columns=['start_date', 'end_date']) # 可选:将日期转为字符串格式(与示例格式一致) result_df['date'] = result_df['date'].dt.strftime('%Y-%m-%d')
方法二:矢量化实现(大数据量优先)
利用numpy的广播和重复机制,避免apply的循环开销,性能更优:
import numpy as np # 计算每个促销活动的天数(包含起止日期) sample_df['days'] = (sample_df['end_date'] - sample_df['start_date']).dt.days + 1 # 重复非日期列对应次数 promo_item_no = np.repeat(sample_df['promo_item_no'].values, sample_df['days'].values) cannibalized = np.repeat(sample_df['cannibalized'].values, sample_df['days'].values) # 生成所有日期序列 dates = [] for _, row in sample_df.iterrows(): dates.extend(pd.date_range(row['start_date'], row['end_date'], freq='D')) # 构建结果DataFrame result_df = pd.DataFrame({ 'date': dates, 'promo_item_no': promo_item_no, 'cannibalized': cannibalized }) # 转为字符串格式日期 result_df['date'] = result_df['date'].dt.strftime('%Y-%m-%d')
结果验证
可以用以下代码验证结果是否与目标一致:
pd.testing.assert_frame_equal(result_df, sample_df2)
内容的提问来源于stack exchange,提问作者Jordan Howell
相关产品推荐
相关产品推荐

