Pandas DataFrame中如何拆分跨多月时间戳间隔并按月份生成新行
解法
我们可以利用Pandas的时间序列生成和explode特性实现全向量化操作,核心思路是先为每个看板的运输区间生成所有跨月分界点,再把分界点与原起止时间拼接后拆分切片得到每段月度区间,整体性能远高于逐行迭代方案,适合大规模数据集使用。
步骤1:预处理时间列
首先把原数据的start、end列转为datetime类型:
import pandas as pd # 原始数据 df = pd.DataFrame({ 'id_kanban': [244, 243, 8, 9, 29], 'component': ['A', 'A', 'B', 'B', 'C'], 'start': ['2021-01-23 11:51:39', '2021-01-28 08:11:48', '2021-01-30 06:32:32', '2021-02-01 11:21:39', '2021-02-02 17:03:18'], 'end': ['2021-02-11 10:20:21', '2021-01-28 09:13:42', '2021-02-02 08:14:24', '2021-04-04 09:22:19', '2021-02-03 13:05:28'] }) # 转换为时间格式 df[['start', 'end']] = df[['start', 'end']].apply(pd.to_datetime)
步骤2:生成所有时间分界点
为每行生成运输区间内所有的月份首日(即跨月切换点),再和原起止时间拼接成完整的时间节点列表:
# 生成每行的跨月分界点列表 df['time_points'] = df.apply( lambda x: [x['start']] + pd.date_range( start=x['start'] + pd.offsets.MonthBegin(1), end=x['end'], freq='MS' ).tolist() + [x['end']], axis=1 ) # 把时间点列表拆分为单独行 df_explode = df.explode('time_points', ignore_index=True)
步骤3:生成拆分后的区间
按看板id分组,将时间点后移一位作为对应区间的结束时间,过滤掉无效的末行空值即可:
# 按看板分组生成区间的结束时间 df_explode['end_new'] = df_explode.groupby('id_kanban')['time_points'].shift(-1) # 过滤空值、重命名列、保留需要的字段 res = df_explode.dropna(subset=['end_new']).rename( columns={'time_points': 'start', 'end_new': 'end'} )[['id_kanban', 'component', 'start', 'end']].reset_index(drop=True)
输出结果验证
最终输出的res和预期结果完全一致:
id_kanban component start end 0 244 A 2021-01-23 11:51:39 2021-02-01 00:00:00 1 244 A 2021-02-01 00:00:00 2021-02-11 10:20:21 2 243 A 2021-01-28 08:11:48 2021-01-28 09:13:42 3 8 B 2021-01-30 06:32:32 2021-02-01 00:00:00 4 8 B 2021-02-01 00:00:00 2021-02-02 08:14:24 5 9 B 2021-02-01 11:21:39 2021-03-01 00:00:00 6 9 B 2021-03-01 00:00:00 2021-04-01 00:00:00 7 9 B 2021-04-01 00:00:00 2021-04-04 09:22:19 8 29 C 2021-02-02 17:03:18 2021-02-03 13:05:28
内容的提问来源于stack exchange,提问作者LazyEval
相关产品推荐
相关产品推荐

