Python Pandas – 检查是否已将CustomBusinessHour Offset归一化
什么是CustomBusinessHour Offset
在介绍 CustomBusinessHour 的归一化之前,我们先来看看什么是 CustomBusinessHour Offset。
当我们处理时间序列数据时,经常需要考虑工作日、节假日等因素对数据造成的影响。Pandas 提供了一个 CustomBusinessHour 类型,来帮助我们处理这种情况。它可以指定一周中的工作日、休息日,以及每日的工作开始时间和结束时间。
例如,我们可以定义一个 CustomBusinessHour 来表示周一至周五的 9:00 到 17:00 是工作时间,而周六周日是休息时间:
from pandas.tseries.offsets import CustomBusinessHour
work_hours = CustomBusinessHour(
weekmask='Mon Tue Wed Thu Fri',
start='09:00',
end='17:00'
)
这样,我们就可以将一个时间戳向前或向后移动指定数量的工作小时:
from datetime import datetime
start_time = datetime(2022, 1, 1, 10, 0)
end_time = start_time + work_hours * 2 # 向后移动 2 个工作小时
CustomBusinessHour Offset 的归一化
当我们使用 CustomBusinessHour 类型来处理时间序列数据时,经常会遇到一个问题:不同的时间戳,可能会落在同一个工作小时内。例如,假设我们有两个时间戳,分别是 2022-01-03 10:30 和 2022-01-03 11:30,它们都落在周一的工作时间内。如果我们直接将它们转换成工作小时的数量,得到的结果是相同的:
from datetime import datetime
start_time_1 = datetime(2022, 1, 3, 10, 30)
start_time_2 = datetime(2022, 1, 3, 11, 30)
print(work_hours.count(start_time_1, start_time_2)) # 输出 1
这可能会导致一些问题,因为这两个时间戳实际上属于不同的工作小时。为了处理这种情况,Pandas 引入了 CustomBusinessHour 的归一化。归一化后,不同的时间戳总是在不同的工作小时内。
例如,我们对上面的例子进行归一化:
normalized_start_time_1 = work_hours.normalize(start_time_1)
normalized_start_time_2 = work_hours.normalize(start_time_2)
print(work_hours.count(normalized_start_time_1, normalized_start_time_2)) # 输出 2
可以看到,经过归一化后,这两个时间戳被分成了两个工作小时。这个例子中只有两个时间戳,但是在实际应用中,时间戳数量可能会非常多,因此归一化是非常重要的。
如何检查是否已将CustomBusinessHour Offset归一化
通常情况下,我们可以通过检查归一化后的 CustomBusinessHour 对象是否等于原始的 CustomBusinessHour 对象,来判断是否已将 CustomBusinessHour 归一化。如果它们相等,说明没有进行归一化,否则就进行了归一化。
例如,对于前面定义的 work_hours,我们可以这样检查它是否已经归一化:
normalized_work_hours = work_hours.normalize()
print(work_hours == normalized_work_hours) # 输出 False
结果为 False,说明 work_hours 已经进行了归一化。如果返回值为 True,则说明还没有进行归一化。
需要注意的是,上面的检查方式对于大部分情况都是有效的,但是也有一些特殊情况,例如如果在定义 CustomBusinessHour 对象时指定了自定义假期,那么归一化后的对象就不等于原始对象,因为归一化会忽略假期的影响。在这种情况下,可以通过检查两个对象的 times 属性是否相等来确定是否进行了归一化:
from pandas.tseries.holiday import USFederalHolidayCalendar
cal = USFederalHolidayCalendar()
work_hours_with_holidays = CustomBusinessHour(
weekmask='Mon Tue Wed Thu Fri',
start='09:00',
end='17:00',
holidays=cal.holidays()
)
normalized_work_hours_with_holidays = work_hours_with_holidays.normalize()
print(work_hours_with_holidays.times == normalized_work_hours_with_holidays.times) # 输出 True
结论
在处理时间序列数据时,使用 CustomBusinessHour 可以方便地处理工作日、休息日等诸多问题。但是由于存在归一化的问题,我们需要在使用时注意检查对象是否已经归一化,以避免出现问题。
极客笔记