如何优化Pandas日期范围转换?寻求高效条件合并方案
问题描述
我有如下销售数据DataFrame,日期列的数据类型为pandas的datetime[64]:
| Shop ID | Special Offer Start | Special Offer End |
|---|---|---|
| A | '2022-01-01' | '2022-01-03' |
| B | '2022-01-09' | '2022-01-11' |
希望将数据转换为二进制格式,用单独列展示日期,促销信息用0和1标识,转换后表格如下:
| Shop ID | Date | Special Offer? |
|---|---|---|
| A | '2022-01-01' | 1 |
| A | '2022-01-02' | 1 |
| A | '2022-01-03' | 1 |
| B | '2022-01-09' | 1 |
| B | '2022-01-10' | 1 |
| B | '2022-01-11' | 1 |
我原本用逐行循环的方式实现,但运行速度极慢:
new_list = [] for i, row in sales_df.iterrows(): df = pd.DataFrame(pd.date_range(start=row["Special Offer Start"],end=row["Special Offer End"]), columns=['Date']) df['Shop ID'] = row['Shop ID'] df["Special Offer?"] = 1 new_list.append(df) result = pd.concat(new_list ).reset_index(drop=True)
我想过先给原DataFrame加Special Offer?列,再和包含所有日期的DataFrame按「Date在Special Offer Start和Special Offer End之间」的条件合并后填充NaN,但找不到Pandas里对应的条件合并方法,求这个日期范围转换的优化方案。
优化方案
方法1:用explode结合date_range生成日期序列
避免逐行循环,直接对每行生成日期范围的列表,再用explode展开,这是Pandas原生的高效操作:
# 为每行生成日期范围的列表 sales_df['Date'] = sales_df.apply( lambda x: pd.date_range(start=x['Special Offer Start'], end=x['Special Offer End']).tolist(), axis=1 ) # 展开列表为多行并整理列 result = sales_df.explode('Date')[['Shop ID', 'Date']] result['Special Offer?'] = 1 result = result.reset_index(drop=True)
方法2:生成全量店铺-日期组合,匹配促销区间(支持非促销日期标记0)
如果需要包含非促销日期并标记为0,可以用笛卡尔积生成全量组合,再判断日期是否在促销区间内:
# 生成所有需要覆盖的日期范围(取原数据中最早和最晚的日期) all_dates = pd.date_range( start=sales_df['Special Offer Start'].min(), end=sales_df['Special Offer End'].max() ) # 生成店铺和日期的笛卡尔积 all_shop_dates = pd.MultiIndex.from_product( [sales_df['Shop ID'].unique(), all_dates], names=['Shop ID', 'Date'] ).to_frame(index=False) # 合并原促销数据,判断每个日期是否属于促销区间 result = all_shop_dates.merge( sales_df, on='Shop ID', how='left' ) # 标记促销状态:日期在区间内为1,否则为0 result['Special Offer?'] = result.apply( lambda x: 1 if (x['Date'] >= x['Special Offer Start']) & (x['Date'] <= x['Special Offer End']) else 0, axis=1 ) # 清理多余列 result = result[['Shop ID', 'Date', 'Special Offer?']].reset_index(drop=True)
方法3:用Numpy广播机制加速(超大数据量适用)
如果数据量极大,用Numpy的广播替代Pandas的行级操作,进一步提升速度:
import numpy as np # 提取数组格式的店铺、起始、结束日期 shops = sales_df['Shop ID'].to_numpy() starts = sales_df['Special Offer Start'].to_numpy().astype('datetime64[D]') ends = sales_df['Special Offer End'].to_numpy().astype('datetime64[D]') # 计算每个促销区间的日期数量,生成重复的店铺数组 date_counts = (ends - starts).astype(int) + 1 repeat_shops = np.repeat(shops, date_counts) # 生成所有促销日期的数组 dates = np.concatenate([np.arange(s, e+np.timedelta64(1, 'D'), dtype='datetime64[D]') for s, e in zip(starts, ends)]) # 组合成结果DataFrame result = pd.DataFrame({ 'Shop ID': repeat_shops, 'Date': dates, 'Special Offer?': 1 })
内容的提问来源于stack exchange,提问作者xstrawarot
相关产品推荐
相关产品推荐

