如何在Pandas DataFrame中拆分跨午夜的时间区间行
拆分Pandas DataFrame中跨午夜的时间区间
嘿,这个需求我之前处理过,其实用Pandas就能轻松搞定!咱们先从重现你的数据开始,然后一步步实现拆分逻辑,最后还会给你一个高效的优化方案。
首先,先把你给的数据构造代码贴出来,方便大家复现:
import pandas as pd # 生成原始DataFrame df = pd.DataFrame(data=pd.date_range('20100201', periods=10, freq='5h3min'), columns=['Start']) df['End'] = df['Start'] + pd.Timedelta(4, 'h')
核心思路
我们的目标是:找出所有Start和End不在同一天的行(也就是跨午夜的区间),把它们拆成两段:
- 第一段从原Start到当天的最后一刻(比如
23:59:59,或者你示例里的23:59:00,这个可以调整) - 第二段从次日的
00:00:00到原End
方案一:直观的循环实现(适合小数据集)
这种方式逻辑清晰,新手也能一眼看懂:
# 先标记哪些行需要拆分 df['cross_midnight'] = df['Start'].dt.date != df['End'].dt.date # 用来存储拆分后的所有行 split_rows = [] # 遍历每一行处理 for _, row in df.iterrows(): if row['cross_midnight']: # 计算当天的结束时间(这里用当天最后一秒,要改成23:59:00就换成pd.Timedelta(minutes=1)) day_end = row['Start'].normalize() + pd.Timedelta(days=1) - pd.Timedelta(seconds=1) # 添加第一段 split_rows.append({'Start': row['Start'], 'End': day_end}) # 计算次日的开始时间 next_day_start = row['Start'].normalize() + pd.Timedelta(days=1) # 添加第二段 split_rows.append({'Start': next_day_start, 'End': row['End']}) else: # 不需要拆分的行直接加入 split_rows.append(row[['Start', 'End']].to_dict()) # 转换成新的DataFrame并重置索引 new_df = pd.DataFrame(split_rows).reset_index(drop=True) # 打印结果看看 print(new_df)
运行后,你会看到原数据中跨午夜的行被成功拆分,和你给出的示例效果一致~
方案二:向量化优化(适合大数据集)
如果你的数据量很大,循环的效率就不够看了,咱们用Pandas的向量化操作来提速:
import pandas as pd # 还是先构造原始数据 df = pd.DataFrame(data=pd.date_range('20100201', periods=10, freq='5h3min'), columns=['Start']) df['End'] = df['Start'] + pd.Timedelta(4, 'h') # 筛选出需要拆分的行 cross_df = df[df['Start'].dt.date != df['End'].dt.date].copy() # 生成拆分后的第一部分(到当天结束) cross_part1 = cross_df.assign(End=cross_df['Start'].dt.normalize() + pd.Timedelta(days=1) - pd.Timedelta(seconds=1)) # 生成拆分后的第二部分(次日开始) cross_part2 = cross_df.assign(Start=cross_df['Start'].dt.normalize() + pd.Timedelta(days=1)) # 合并不需要拆分的行 + 拆分后的两部分 new_df = pd.concat( [df[df['Start'].dt.date == df['End'].dt.date], cross_part1, cross_part2], ignore_index=True ) # 按Start时间重新排序(保证顺序和原数据一致) new_df = new_df.sort_values('Start').reset_index(drop=True) print(new_df)
这种方式完全不用循环,利用Pandas的批量处理能力,速度能提升好几倍,处理十万级以上的数据也毫无压力。
小调整:匹配你示例中的23:59:00
如果你想和示例一样把当天结束时间设为23:59:00,只需要把计算day_end的代码改成:
day_end = row['Start'].normalize() + pd.Timedelta(days=1) - pd.Timedelta(minutes=1)
这样就完美匹配你的输出要求啦!
内容的提问来源于stack exchange,提问作者00__00__00
相关产品推荐
相关产品推荐

