Python Pandas:如何使用date_range向量化函数?
向量化处理Pandas中基于日期区间的展开需求
我明白你想要把每行的START_DATE到STOP_DATE区间展开成连续的日期记录,同时保留对应的KEY和AMOUNT,而且希望用向量化的方式实现,避免低效的循环——这在处理大数据量时尤为关键。下面是两种实用的高效实现方案:
方法一:简洁版(apply + explode,适合中小数据量)
这种写法代码简洁易懂,适合数据规模不大的场景:
import pandas as pd df = pd.DataFrame({ 'KEY': [1, 2, 3, 1, 1, 2], 'START_DATE': ['2018-01-05', '2018-01-04', '2018-01-01', '2018-01-23', '2018-02-01', '2018-03-11'], 'STOP_DATE': ['2018-01-22', '2018-03-10', '2018-01-31', '2018-02-15', '2018-04-01', '2018-07-21'], 'AMOUNT': [5, 3, 11, 14, 7, 9], }) df.START_DATE = pd.to_datetime(df.START_DATE, format='%Y-%m-%d') df.STOP_DATE = pd.to_datetime(df.STOP_DATE, format='%Y-%m-%d') # 为每行生成日期区间的列表 df['DATE'] = df.apply(lambda row: pd.date_range(row['START_DATE'], row['STOP_DATE'], freq='D'), axis=1) # 展开日期列表,同时保留其他字段 expanded_df = df.explode('DATE').drop(columns=['START_DATE', 'STOP_DATE']) # 调整列顺序(可选) expanded_df = expanded_df[['KEY', 'DATE', 'AMOUNT']] # 查看结果 print(expanded_df.head())
输出示例:
KEY DATE AMOUNT 0 1 2018-01-05 5 1 1 2018-01-06 5 2 1 2018-01-07 5 3 1 2018-01-08 5 4 1 2018-01-09 5
方法二:纯向量化实现(适合大数据量,效率拉满)
如果你的数据规模很大(比如几十万行以上),上面的apply本质还是逐行操作,效率会受限。这种纯向量化的方案完全依赖Pandas的批量操作,速度会快很多:
import pandas as pd df = pd.DataFrame({ 'KEY': [1, 2, 3, 1, 1, 2], 'START_DATE': ['2018-01-05', '2018-01-04', '2018-01-01', '2018-01-23', '2018-02-01', '2018-03-11'], 'STOP_DATE': ['2018-01-22', '2018-03-10', '2018-01-31', '2018-02-15', '2018-04-01', '2018-07-21'], 'AMOUNT': [5, 3, 11, 14, 7, 9], }) df.START_DATE = pd.to_datetime(df.START_DATE, format='%Y-%m-%d') df.STOP_DATE = pd.to_datetime(df.STOP_DATE, format='%Y-%m-%d') # 计算每个日期区间的天数(+1是因为要包含起始和结束日期) df['DURATION'] = (df['STOP_DATE'] - df['START_DATE']).dt.days + 1 # 按DURATION的值重复每行,生成基础展开表 expanded_df = df.loc[df.index.repeat(df['DURATION'])].copy() # 计算每个重复行在原行中的偏移量(从0开始) expanded_df['OFFSET'] = expanded_df.groupby(expanded_df.index).cumcount() # 根据偏移量计算对应日期 expanded_df['DATE'] = expanded_df['START_DATE'] + pd.to_timedelta(expanded_df['OFFSET'], unit='D') # 清理不需要的列并调整顺序 expanded_df = expanded_df.drop(columns=['START_DATE', 'STOP_DATE', 'DURATION', 'OFFSET']) expanded_df = expanded_df[['KEY', 'DATE', 'AMOUNT']].reset_index(drop=True) # 查看结果 print(expanded_df.head())
额外说明
- 如果需要按其他频率(比如周
freq='W'、月freq='M')展开,方法一中只需修改pd.date_range的freq参数;方法二中则需要调整DURATION的计算逻辑和timedelta的单位。 - 两种方法最终的输出结构完全一致,你可以根据自己的数据规模选择合适的方案。
内容的提问来源于stack exchange,提问作者Prikers
相关产品推荐
相关产品推荐

