Pandas技术实操:如何筛选date_range中不属于Interval列预留时间区间的时段
解决思路与代码实现
首先得说清楚你遇到的问题根源:你用pd.Timestamp(...) in df.reserved返回False,是因为这里的in操作符是在检查该时间戳是否是reserved列中的某一个区间对象,而不是检查时间戳是否落在某个区间范围内,所以肯定会返回False,这是个常见的逻辑误区。
下面给出两种可行的解决方案,先提个小细节:你的示例里df的区间是2011年,但working_hours生成的是2021年,这两个完全不重叠,我先把时间统一成2011年,保证结果符合你预期的示例输出。
方法一:批量检查(高效推荐)
利用pandas的IntervalIndex来批量处理,效率很高,适合大数据集:
import pandas as pd # 初始化已占用区间的DataFrame(统一为2011年) df = pd.DataFrame( { 'reserved': [ pd.Interval(pd.Timestamp(2011,11,9,8), pd.Timestamp(2011,11,9,12), closed='left'), pd.Interval(pd.Timestamp(2011,11,9,13), pd.Timestamp(2011,11,9,21), closed='left') ], 'value': [1, 2] }) # 生成当日工作时段的小时级时间序列(2011年) working_hours = pd.date_range('2011-11-09 07', '2011-11-09 23', freq='1H') # 将reserved列转换为IntervalIndex,方便批量操作 reserved_intervals = pd.IntervalIndex(df['reserved']) # 批量判断每个时间点是否落在任意一个已占用区间内 # any(axis=1)表示只要该时间点在任意一个区间内,就标记为已占用 is_reserved = reserved_intervals.contains(working_hours).any(axis=1) # 筛选出未被预留的时间点(取反操作~) free_hours = working_hours[~is_reserved] print(free_hours)
运行后输出的结果正好是你预期的未被预留时段:
DatetimeIndex(['2011-11-09 07:00:00', '2011-11-09 12:00:00', '2011-11-09 21:00:00', '2011-11-09 22:00:00'], dtype='datetime64[ns]', freq=None)
方法二:逐个判断(逻辑直观,适合小数据集)
如果你的数据集不大,也可以用apply逐个检查每个时间点是否落在任何已占用区间里,逻辑更易懂:
import pandas as pd # 同样先初始化数据和时间序列(省略重复代码,和上面一致) df = pd.DataFrame( { 'reserved': [ pd.Interval(pd.Timestamp(2011,11,9,8), pd.Timestamp(2011,11,9,12), closed='left'), pd.Interval(pd.Timestamp(2011,11,9,13), pd.Timestamp(2011,11,9,21), closed='left') ], 'value': [1, 2] }) working_hours = pd.date_range('2011-11-09 07', '2011-11-09 23', freq='1H') # 定义一个函数,检查单个时间戳是否在任意已占用区间内 def is_in_reserved(ts): return any(ts in interval for interval in df['reserved']) # 对每个时间点应用函数,得到是否已被预留的布尔序列 is_reserved = pd.Series(working_hours).apply(is_in_reserved) # 筛选未被预留的时间点 free_hours = working_hours[~is_reserved]
这个方法的逻辑和你最初尝试的思路更接近,但因为是循环逐个判断,大数据量下效率会比方法一低一些。
内容的提问来源于stack exchange,提问作者user3225309
相关产品推荐
相关产品推荐

