Pandas 时间序列 - DateOffset 对象

点击上方“Python爬虫与数据挖掘”,进行关注

回复“书籍”即可获赠Python从入门到进阶共10本电子书

国亡身殒今何有,只留离骚在世间。

呆鸟云:“书接上文《Pandas 时间序列 - 日期时间索引》,本篇讲的主要是日期偏移,就是标题里的 DateOffset。这里呆鸟强调一下,文章光看不行,一定要敲代码,左右分屏,一边放文章,一边敲代码,一段一段代码敲出来,看每一段运行的结果,这样能更好理解代码的含义,才能学的更扎实。还有,官档精译系列是全面基础知识,百问百答系列是实战技巧,两个系列要配合着学才好。”

今天换个浅色的代码主题。

呆鸟又云:“感谢大家支持,上一篇《三分钟告诉你 1575119387982 是什么?》” 的在看突破了 50+。呆鸟辛苦翻译,写文,公号也没留言功能,看到在看,才知道有多少读者对呆鸟文章的认可,在看多, 就是读者对呆鸟的鼓励,就更有动力继续下去,所以继续求在看,希望这篇的在看也能上50+”,不知道在看在哪里的,在文章最下方找,见下图。

参数偏移`Series` 与 `DatetimeIndex` 偏移自定义工作日工作时间自定义工作时间偏移量别名别名组合锚定偏移量锚定偏移量的含义假日与节日日历

上例中,频率字符串(如,D)用于定义指定的频率:

  • date_range() 按指定频率分隔 DatetimeIndex 里的日期与时间

  • `Period` 或 `PeriodIndex` 的频率

频率字符串表示的是 DateOffset 对象及其子类。DateOffset 类似于时间差 Timedelta ,但遵循指定的日历日规则。例如,Timedelta 表示的每日时间差一直都是 24 小时,而 DateOffset 的每日偏移量则是与下一天相同的时间差,使用夏时制时,每日偏移时间有可能是 23 或 24 小时,甚至还有可能是 25 小时。不过,DateOffset 子类只能是等于或小于小时的时间单位(HourMinuteSecondMilliMicroNano),操作类似于 Timedelta 及对应的绝对时间。

DateOffset 基础操作类似于 dateutil.relativedelta(relativedelta 文档),可按指定的日历日时间段偏移日期时间。可用算数运算符(+)或 apply 方法执行日期偏移操作。

# 指定包含夏时制变迁的某天
In [141]: ts = pd.Timestamp('2016-10-30 00:00:00', tz='Europe/Helsinki')

# 对应的绝对时间
In [142]: ts + pd.Timedelta(days=1)
Out[142]: Timestamp('2016-10-30 23:00:00+0200', tz='Europe/Helsinki')

# 对应的日历时间
In [143]: ts + pd.DateOffset(days=1)
Out[143]: Timestamp('2016-10-31 00:00:00+0200', tz='Europe/Helsinki')

In [144]: friday = pd.Timestamp('2018-01-05')

In [145]: friday.day_name()
Out[145]: 'Friday'

# 与两个工作日相加(星期五 --> 星期二)
In [146]: two_business_days = 2 * pd.offsets.BDay()

In [147]: two_business_days.apply(friday)
Out[147]: Timestamp('2018-01-09 00:00:00')

In [148]: friday + two_business_days
Out[148]: Timestamp('2018-01-09 00:00:00')

In [149]: (friday + two_business_days).day_name()
Out[149]: 'Tuesday'

大多数 DateOffset 都支持频率字符串或偏移别名,可用作 freq 关键字参数。有效的日期偏移及频率字符串如下:

日期偏移量频率字符串说明
DateOffset通用偏移类,默认为一个日历日
BDayBusinessDay'B'工作日
CDayCustomBusinessDay'C'自定义工作日
Week'W'一周,可选周内固定某日
WeekOfMonth'WOM'每月第几周的第几天
LastWeekOfMonth'LWOM'每月最后一周的第几天
MonthEnd'M'日历日月末
MonthBegin'MS'日历日月初
BMonthEndBusinessMonthEnd'BM'工作日月末
BMonthBeginBusinessMonthBegin'BMS'工作日月初
CBMonthEndCustomBusinessMonthEnd'CBM'自定义工作日月末
CBMonthBeginCustomBusinessMonthBegin'CBMS'自定义工作日月初
SemiMonthEnd'SM'某月第 15 天(或其它半数日期)与日历日月末
SemiMonthBegin'SMS'日历日月初与第 15 天(或其它半数日期)
QuarterEnd'Q'日历日季末
QuarterBegin'QS'日历日季初
BQuarterEnd'BQ工作日季末
BQuarterBegin'BQS'工作日季初
FY5253Quarter'REQ'零售季,又名 52-53 周
YearEnd'A'日历日年末
YearBegin'AS''BYS'日历日年初
BYearEnd'BA'工作日年末
BYearBegin'BAS'工作日年初
FY5253'RE'零售年(又名 52-53 周)
Easter复活节假日
BusinessHour'BH'工作小时
CustomBusinessHour'CBH'自定义工作小时
Day'D'一天
Hour'H'一小时
Minute'T''min'一分钟
Second'S'一秒
Milli'L''ms'一毫秒
Micro'U''us'一微秒
Nano'N'一纳秒

DateOffset 还支持 rollforward()rollback() 方法,按偏移量把某一日期向前向后移动至有效偏移日期。例如,工作日偏移滚动日期时会跳过周末(即,星期六与星期日),直接到星期一,因为工作日偏移针对的是工作日。

In [150]: ts = pd.Timestamp('2018-01-06 00:00:00')

In [151]: ts.day_name()
Out[151]: 'Saturday'

# 工作时间的有效偏移日期为星期一至星期五
In [152]: offset = pd.offsets.BusinessHour(start='09:00')

# 向前偏移到最近的工作日,即星期一
In [153]: offset.rollforward(ts)
Out[153]: Timestamp('2018-01-08 09:00:00')

# 向前偏移至最近的工作日,同时,小时也相应增加了
In [154]: ts + offset
Out[154]: Timestamp('2018-01-08 10:00:00')

这些操作默认保存时间(小时、分钟等)信息。normalize() 可以把时间重置为午夜零点,是否应用此操作,取决于是否需要保留时间信息。

In [155]: ts = pd.Timestamp('2014-01-01 09:00')

In [156]: day = pd.offsets.Day()

In [157]: day.apply(ts)
Out[157]: Timestamp('2014-01-02 09:00:00')

In [158]: day.apply(ts).normalize()
Out[158]: Timestamp('2014-01-02 00:00:00')

In [159]: ts = pd.Timestamp('2014-01-01 22:00')

In [160]: hour = pd.offsets.Hour()

In [161]: hour.apply(ts)
Out[161]: Timestamp('2014-01-01 23:00:00')

In [162]: hour.apply(ts).normalize()
Out[162]: Timestamp('2014-01-01 00:00:00')

In [163]: hour.apply(pd.Timestamp("2014-01-01 23:30")).normalize()
Out[163]: Timestamp('2014-01-02 00:00:00')

参数偏移

偏移量支持参数,可以让不同操作生成不同结果。例如,Week 偏移生成每周数据时支持 weekday 参数,生成日期始终位于一周中的指定日期。

In [164]: d = datetime.datetime(2008, 8, 18, 9, 0)

In [165]: d
Out[165]: datetime.datetime(2008, 8, 18, 9, 0)

In [166]: d + pd.offsets.Week()
Out[166]: Timestamp('2008-08-25 09:00:00')

In [167]: d + pd.offsets.Week(weekday=4)
Out[167]: Timestamp('2008-08-22 09:00:00')

In [168]: (d + pd.offsets.Week(weekday=4)).weekday()
Out[168]: 4

In [169]: d - pd.offsets.Week()
Out[169]: Timestamp('2008-08-11 09:00:00')

加减法也支持 normalize 选项。

In [170]: d + pd.offsets.Week(normalize=True)
Out[170]: Timestamp('2008-08-25 00:00:00')

In [171]: d - pd.offsets.Week(normalize=True)
Out[171]: Timestamp('2008-08-11 00:00:00')

YearEnd 也支持参数,如 month 参数,用于指定月份 。

In [172]: d + pd.offsets.YearEnd()
Out[172]: Timestamp('2008-12-31 09:00:00')

In [173]: d + pd.offsets.YearEnd(month=6)
Out[173]: Timestamp('2009-06-30 09:00:00')

`Series` 与 `DatetimeIndex` 偏移

可以为 SeriesDatetimeIndex 里的每个元素应用偏移。

In [174]: rng = pd.date_range('2012-01-01', '2012-01-03')

In [175]: s = pd.Series(rng)

In [176]: rng
Out[176]: DatetimeIndex(['2012-01-01', '2012-01-02', '2012-01-03'], dtype='datetime64[ns]', freq='D')

In [177]: rng + pd.DateOffset(months=2)
Out[177]: DatetimeIndex(['2012-03-01', '2012-03-02', '2012-03-03'], dtype='datetime64[ns]', freq='D')

In [178]: s + pd.DateOffset(months=2)
Out[178]: 
0   2012-03-01
1   2012-03-02
2   2012-03-03
dtype: datetime64[ns]

In [179]: s - pd.DateOffset(months=2)
Out[179]: 
0   2011-11-01
1   2011-11-02
2   2011-11-03
dtype: datetime64[ns]

如果偏移直接映射 TimedeltaDayHourMinuteSecondMicroMilliNano),则该偏移与 Timedelta 的使用方式完全一样。参阅时间差 - Timedelta,查看更多示例。

In [180]: s - pd.offsets.Day(2)
Out[180]: 
0   2011-12-30
1   2011-12-31
2   2012-01-01
dtype: datetime64[ns]

In [181]: td = s - pd.Series(pd.date_range('2011-12-29', '2011-12-31'))

In [182]: td
Out[182]: 
0   3 days
1   3 days
2   3 days
dtype: timedelta64[ns]

In [183]: td + pd.offsets.Minute(15)
Out[183]: 
0   3 days 00:15:00
1   3 days 00:15:00
2   3 days 00:15:00
dtype: timedelta64[ns]

注意,某些偏移量(如 BQuarterEnd)不支持矢量操作,即使可以执行运算,速度也非常慢,并可能显示 PerformanceWaring(性能警告)。

In [184]: rng + pd.offsets.BQuarterEnd()
Out[184]: DatetimeIndex(['2012-03-30', '2012-03-30', '2012-03-30'], dtype='datetime64[ns]', freq='D')

自定义工作日

CdayCustomBusinessDay 类可以参数化 BusinessDay 类,用于创建支持本地周末与传统节假日的自定义工作日历。

下面这个例子就很有意思,知道吗?埃及的周末是星期五与星期六。

In [185]: weekmask_egypt = 'Sun Mon Tue Wed Thu'


# 下面是 2012 - 2014 年的五一劳动节
In [186]: holidays = ['2012-05-01',
   .....:             datetime.datetime(2013, 5, 1),
   .....:             np.datetime64('2014-05-01')]
   .....: 

In [187]: bday_egypt = pd.offsets.CustomBusinessDay(holidays=holidays,
   .....:                                           weekmask=weekmask_egypt)
   .....: 

In [188]: dt = datetime.datetime(2013, 4, 30)

In [189]: dt + 2 * bday_egypt
Out[189]: Timestamp('2013-05-05 00:00:00')

下列代码实现了日期与工作日之间的映射关系。

In [190]: dts = pd.date_range(dt, periods=5, freq=bday_egypt)

In [191]: pd.Series(dts.weekday, dts).map(
   .....:     pd.Series('Mon Tue Wed Thu Fri Sat Sun'.split()))
   .....: 
Out[191]: 
2013-04-30    Tue
2013-05-02    Thu
2013-05-05    Sun
2013-05-06    Mon
2013-05-07    Tue
Freq: C, dtype: object

节日日历支持节假日列表。更多信息,请参阅节日日历文档。

In [192]: from pandas.tseries.holiday import USFederalHolidayCalendar

In [193]: bday_us = pd.offsets.CustomBusinessDay(calendar=USFederalHolidayCalendar())

# 马丁路德金纪念日前的星期五
In [194]: dt = datetime.datetime(2014, 1, 17)

# 马丁路德金纪念日后的星期二,因为星期一放假,所以跳过了
In [195]: dt + bday_us
Out[195]: Timestamp('2014-01-21 00:00:00')

遵循节日日历规则的月偏移可以用正常方式定义。

In [196]: bmth_us = pd.offsets.CustomBusinessMonthBegin(
   .....:     calendar=USFederalHolidayCalendar())
   .....: 

# 跳过新年
In [197]: dt = datetime.datetime(2013, 12, 17)

In [198]: dt + bmth_us
Out[198]: Timestamp('2014-01-02 00:00:00')

# 定义带自定义偏移的日期索引
In [199]: pd.date_range(start='20100101', end='20120101', freq=bmth_us)
Out[199]: 
DatetimeIndex(['2010-01-04', '2010-02-01', '2010-03-01', '2010-04-01',
               '2010-05-03', '2010-06-01', '2010-07-01', '2010-08-02',
               '2010-09-01', '2010-10-01', '2010-11-01', '2010-12-01',
               '2011-01-03', '2011-02-01', '2011-03-01', '2011-04-01',
               '2011-05-02', '2011-06-01', '2011-07-01', '2011-08-01',
               '2011-09-01', '2011-10-03', '2011-11-01', '2011-12-01'],
              dtype='datetime64[ns]', freq='CBMS')

注意:频率字符串 'C' 验证 CustomBusinessDay 日期偏移 调用,注意,CustomBusinessDay 可实现参数化,CustomBusinessDay 实例会各不相同,且频率字符串 'C' 无法识别这个问题。用户应确保应用里调用的频率字符串 'C' 的一致性 。

工作时间

BusinessHour 表示 BusinessDay 基础上的工作时间,用于指定开始与结束工作时间。

BusinessHour 默认的工作时间是 9:00 - 17:00。BusinessHour 加法以小时频率增加 Timestamp 。如果目标 Timestamp 超出了一小时,则要先移动到下一个工作小时,再行增加。如果超过了当日工作时间的范围,剩下的时间则添加到下一个工作日。

In [200]: bh = pd.offsets.BusinessHour()

In [201]: bh
Out[201]: <BusinessHour: BH=09:00-17:00>

# 2014 年 8 月 1 日是星期五
In [202]: pd.Timestamp('2014-08-01 10:00').weekday()
Out[202]: 4

In [203]: pd.Timestamp('2014-08-01 10:00') + bh
Out[203]: Timestamp('2014-08-01 11:00:00')

# 下例等同于:pd.Timestamp('2014-08-01 09:00') + bh
In [204]: pd.Timestamp('2014-08-01 08:00') + bh
Out[204]: Timestamp('2014-08-01 10:00:00')

# 如果计算结果为当日下班时间,则转移到下一个工作日的上班时间
In [205]: pd.Timestamp('2014-08-01 16:00') + bh
Out[205]: Timestamp('2014-08-04 09:00:00')

# 剩下的时间也会添加到下一天
In [206]: pd.Timestamp('2014-08-01 16:30') + bh
Out[206]: Timestamp('2014-08-04 09:30:00')

# 添加 2 个工作小时
In [207]: pd.Timestamp('2014-08-01 10:00') + pd.offsets.BusinessHour(2)
Out[207]: Timestamp('2014-08-01 12:00:00')

# 减掉 3 个工作小时
In [208]: pd.Timestamp('2014-08-01 10:00') + pd.offsets.BusinessHour(-3)
Out[208]: Timestamp('2014-07-31 15:00:00')

还可以用关键字指定 startend 时间。参数必须是hour:minute 格式的字符串或 datetime.time 实例。把秒、微秒、纳秒设置为工作时间会导致 ValueError

In [209]: bh = pd.offsets.BusinessHour(start='11:00', end=datetime.time(20, 0))

In [210]: bh
Out[210]: <BusinessHour: BH=11:00-20:00>

In [211]: pd.Timestamp('2014-08-01 13:00') + bh
Out[211]: Timestamp('2014-08-01 14:00:00')

In [212]: pd.Timestamp('2014-08-01 09:00') + bh
Out[212]: Timestamp('2014-08-01 12:00:00')

In [213]: pd.Timestamp('2014-08-01 18:00') + bh
Out[213]: Timestamp('2014-08-01 19:00:00')

start 时间晚于 end 时间表示夜班工作时间。此时,工作时间将从午夜延至第二天。工作时间是否有效取决于该时间是否开始于有效的 BusinessDay

In [214]: bh = pd.offsets.BusinessHour(start='17:00', end='09:00')

In [215]: bh
Out[215]: <BusinessHour: BH=17:00-09:00>

In [216]: pd.Timestamp('2014-08-01 17:00') + bh
Out[216]: Timestamp('2014-08-01 18:00:00')

In [217]: pd.Timestamp('2014-08-01 23:00') + bh
Out[217]: Timestamp('2014-08-02 00:00:00')

# 虽然 2014 年 8 月 2 日是星期六,
# 但因为工作时间开始于星期五,因此,也是有效的
In [218]: pd.Timestamp('2014-08-02 04:00') + bh
Out[218]: Timestamp('2014-08-02 05:00:00')


# 虽然 2014 年 8 月 4 日是星期一,
# 但开始时间是星期日,因此,超出了工作时间
In [219]: pd.Timestamp('2014-08-04 04:00') + bh
Out[219]: Timestamp('2014-08-04 18:00:00')

BusinessHour.rollforwardrollback 操作将前滚至下一天的上班时间,或回滚至前一天的下班时间。与其它偏移量不同,BusinessHour.rollforward 输出与 apply 定义不同的结果。

这是因为一天工作时间的结束等同于第二天工作时间的开始。默认情况下,工作时间为 9:00 - 17:00,pandas 认为 2014-08-01 17:002014-08-04 09:00 之间的时间间隔为 0 分钟。

# 把时间戳回滚到前一天的下班时间
In [220]: pd.offsets.BusinessHour().rollback(pd.Timestamp('2014-08-02 15:00'))
Out[220]: Timestamp('2014-08-01 17:00:00')

# 把时间戳前滚到下一个工作日的上班时间
In [221]: pd.offsets.BusinessHour().rollforward(pd.Timestamp('2014-08-02 15:00'))
Out[221]: Timestamp('2014-08-04 09:00:00')

# 等同于:BusinessHour().apply(pd.Timestamp('2014-08-01 17:00'))
# 与 BusinessHour().apply(pd.Timestamp('2014-08-04 09:00'))
In [222]: pd.offsets.BusinessHour().apply(pd.Timestamp('2014-08-02 15:00'))
Out[222]: Timestamp('2014-08-04 10:00:00')

# 工作日的结果(仅供参考)
In [223]: pd.offsets.BusinessHour().rollforward(pd.Timestamp('2014-08-02'))
Out[223]: Timestamp('2014-08-04 09:00:00')

# 等同于 BusinessDay().apply(pd.Timestamp('2014-08-01'))
# 等同于 rollforward 因为工作日不会重叠
In [224]: pd.offsets.BusinessHour().apply(pd.Timestamp('2014-08-02'))
Out[224]: Timestamp('2014-08-04 10:00:00')

BusinessHour 把星期六与星期日当成假日。CustomBusinessHour 可以把节假日设为工作时间,详见下文。

自定义工作时间

0.18.1 版新增

CustomBusinessHourBusinessHourCustomBusinessDay 的混合体,可以指定任意节假日。除了跳过自定义节假日之外,CustomBusinessHour 的运作方式与 BusinessHour 一样。

In [225]: from pandas.tseries.holiday import USFederalHolidayCalendar

In [226]: bhour_us = pd.offsets.CustomBusinessHour(calendar=USFederalHolidayCalendar())

# 马丁路德金纪念日之前的星期五
In [227]: dt = datetime.datetime(2014, 1, 17, 15)

In [228]: dt + bhour_us
Out[228]: Timestamp('2014-01-17 16:00:00')

# 跳至马丁路德金纪念日之后的星期二,星期一过节,所以跳过了
In [229]: dt + bhour_us * 2
Out[229]: Timestamp('2014-01-21 09:00:00')

BusinessHour 支持与 CustomBusinessDay 一样的关键字参数。

In [230]: bhour_mon = pd.offsets.CustomBusinessHour(start='10:00',
   .....:                                           weekmask='Tue Wed Thu Fri')
   .....: 

# 跳过了星期一,因为星期一过节,工作时间从 10 点开始
In [231]: dt + bhour_mon * 2
Out[231]: Timestamp('2014-01-21 10:00:00')

偏移量别名

时间序列频率的字符串别名在这里叫偏移量别名

别名说明
B工作日频率
C自定义工作日频率
D日历日频率
W周频率
M月末频率
SM半月末频率(15 号与月末)
BM工作日月末频率
CBM自定义工作日月末频率
MS月初频率
SMS半月初频率(1 号与 15 号)
BMS工作日月初频率
CBMS自定义工作日月初频率
Q季末频率
BQ工作日季末频率
QS季初频率
BQS工作日季初频率
A, Y年末频率
BA, BY工作日年末频率
AS, YS年初频率
BAS, BYS工作日年初频率
BH工作时间频率
H小时频率
T, min分钟频率
S秒频率
L, ms毫秒
U, us微秒
N纳秒

别名组合

如前说述,别名与偏移量实例在绝大多数函数里可以互换:

In [232]: pd.date_range(start, periods=5, freq='B')
Out[232]: 
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
               '2011-01-07'],
              dtype='datetime64[ns]', freq='B')

In [233]: pd.date_range(start, periods=5, freq=pd.offsets.BDay())
Out[233]: 
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
               '2011-01-07'],
              dtype='datetime64[ns]', freq='B')

可以组合日与当日偏移量。

In [234]: pd.date_range(start, periods=10, freq='2h20min')
Out[234]: 
DatetimeIndex(['2011-01-01 00:00:00', '2011-01-01 02:20:00',
               '2011-01-01 04:40:00', '2011-01-01 07:00:00',
               '2011-01-01 09:20:00', '2011-01-01 11:40:00',
               '2011-01-01 14:00:00', '2011-01-01 16:20:00',
               '2011-01-01 18:40:00', '2011-01-01 21:00:00'],
              dtype='datetime64[ns]', freq='140T')

In [235]: pd.date_range(start, periods=10, freq='1D10U')
Out[235]: 
DatetimeIndex([       '2011-01-01 00:00:00', '2011-01-02 00:00:00.000010',
               '2011-01-03 00:00:00.000020', '2011-01-04 00:00:00.000030',
               '2011-01-05 00:00:00.000040', '2011-01-06 00:00:00.000050',
               '2011-01-07 00:00:00.000060', '2011-01-08 00:00:00.000070',
               '2011-01-09 00:00:00.000080', '2011-01-10 00:00:00.000090'],
              dtype='datetime64[ns]', freq='86400000010U')

锚定偏移量

可以指定某些频率的锚定后缀:

别名说明
W-SUN周频率(星期日),与 “W” 相同
W-MON周频率(星期一)
W-TUE周频率(星期二)
W-WED周频率(星期三)
W-THU周频率(星期四)
W-FRI周频率(星期五)
W-SAT周频率(星期六)
(B)Q(S)-DEC季频率,该年结束于十二月,与 “Q” 相同
(B)Q(S)-JAN季频率,该年结束于一月
(B)Q(S)-FEB季频率,该年结束于二月
(B)Q(S)-MAR季频率,该年结束于三月
(B)Q(S)-APR季频率,该年结束于四月
(B)Q(S)-MAY季频率,该年结束于五月
(B)Q(S)-JUN季频率,该年结束于六月
(B)Q(S)-JUL季频率,该年结束于七月
(B)Q(S)-AUG季频率,该年结束于八月
(B)Q(S)-SEP季频率,该年结束于九月
(B)Q(S)-OCT季频率,该年结束于十月
(B)Q(S)-NOV季频率,该年结束于十一月
(B)A(S)-DEC年频率,锚定结束于十二月,与 “A” 相同
(B)A(S)-JAN年频率,锚定结束于一月
(B)A(S)-FEB年频率,锚定结束于二月
(B)A(S)-MAR年频率,锚定结束于三月
(B)A(S)-APR年频率,锚定结束于四月
(B)A(S)-MAY年频率,锚定结束于五月
(B)A(S)-JUN年频率,锚定结束于六月
(B)A(S)-JUL年频率,锚定结束于七月
(B)A(S)-AUG年频率,锚定结束于八月
(B)A(S)-SEP年频率,锚定结束于九月
(B)A(S)-OCT年频率,锚定结束于十月
(B)A(S)-NOV年频率,锚定结束于十一月

这些别名可以用作 date_rangebdate_rangeDatetimeIndex 及其它时间序列函数的参数。

锚定偏移量的含义

对于偏移量锚定于开始或结束指定频率(MonthEndMonthBeginWeekEnd 等)下列规则应用于前滚与后滚。

n 不为 0 时,如果给定日期不是锚定日期,将寻找下一个或上一个锚点,并向前或向后移动 |n|-1 步。

In [236]: pd.Timestamp('2014-01-02') + pd.offsets.MonthBegin(n=1)
Out[236]: Timestamp('2014-02-01 00:00:00')

In [237]: pd.Timestamp('2014-01-02') + pd.offsets.MonthEnd(n=1)
Out[237]: Timestamp('2014-01-31 00:00:00')

In [238]: pd.Timestamp('2014-01-02') - pd.offsets.MonthBegin(n=1)
Out[238]: Timestamp('2014-01-01 00:00:00')

In [239]: pd.Timestamp('2014-01-02') - pd.offsets.MonthEnd(n=1)
Out[239]: Timestamp('2013-12-31 00:00:00')

In [240]: pd.Timestamp('2014-01-02') + pd.offsets.MonthBegin(n=4)
Out[240]: Timestamp('2014-05-01 00:00:00')

In [241]: pd.Timestamp('2014-01-02') - pd.offsets.MonthBegin(n=4)
Out[241]: Timestamp('2013-10-01 00:00:00')

如果给定日期是锚定日期,则向前(或向后)移动 |n| 个点。

In [242]: pd.Timestamp('2014-01-01') + pd.offsets.MonthBegin(n=1)
Out[242]: Timestamp('2014-02-01 00:00:00')

In [243]: pd.Timestamp('2014-01-31') + pd.offsets.MonthEnd(n=1)
Out[243]: Timestamp('2014-02-28 00:00:00')

In [244]: pd.Timestamp('2014-01-01') - pd.offsets.MonthBegin(n=1)
Out[244]: Timestamp('2013-12-01 00:00:00')

In [245]: pd.Timestamp('2014-01-31') - pd.offsets.MonthEnd(n=1)
Out[245]: Timestamp('2013-12-31 00:00:00')

In [246]: pd.Timestamp('2014-01-01') + pd.offsets.MonthBegin(n=4)
Out[246]: Timestamp('2014-05-01 00:00:00')

In [247]: pd.Timestamp('2014-01-31') - pd.offsets.MonthBegin(n=4)
Out[247]: Timestamp('2013-10-01 00:00:00')

n=0 时,如果日期在锚点,则不移动,否则将前滚至下一个锚点。

In [248]: pd.Timestamp('2014-01-02') + pd.offsets.MonthBegin(n=0)
Out[248]: Timestamp('2014-02-01 00:00:00')

In [249]: pd.Timestamp('2014-01-02') + pd.offsets.MonthEnd(n=0)
Out[249]: Timestamp('2014-01-31 00:00:00')

In [250]: pd.Timestamp('2014-01-01') + pd.offsets.MonthBegin(n=0)
Out[250]: Timestamp('2014-01-01 00:00:00')

In [251]: pd.Timestamp('2014-01-31') + pd.offsets.MonthEnd(n=0)
Out[251]: Timestamp('2014-01-31 00:00:00')

假日与节日日历

用假日与日历可以轻松定义 CustomBusinessDay 假日规则,或其它分析所需的预设假日。AbstractHolidayCalendar 类支持所有返回假日列表的方法,并且仅需在指定假日日历类里定义 rulesstart_dateend_date 类属性决定了假日的范围。该操作会覆盖 AbstractHolidayCalendar 类,适用于所有日历子类。USFederalHolidayCalendar 是仅有的假日日历,主要用作开发其它日历的示例。

固定日期的假日,如美国阵亡将士纪念日或美国国庆日(7 月 4 日),取决于该假日是否是在周末,可以使用以下规则:

规则说明
nearest_workday把星期六移至星期五,星期日移至星期一
sunday_to_monday星期六紧接着星期一
next_monday_or_tuesday把星期六移至星期一,并把星期日/星期一移至星期二
previous_friday把星期六与星期日移至上一个星期五
next_monday把星期六与星期日移至下一个星期一

下例展示如何定义假日与假日日历:

In [252]: from pandas.tseries.holiday import Holiday, USMemorialDay,\
   .....:     AbstractHolidayCalendar, nearest_workday, MO
   .....: 

In [253]: class ExampleCalendar(AbstractHolidayCalendar):
   .....:     rules = [
   .....:         USMemorialDay,
   .....:         Holiday('July 4th', month=7, day=4, observance=nearest_workday),
   .....:         Holiday('Columbus Day', month=10, day=1,
   .....:                 offset=pd.DateOffset(weekday=MO(2)))]
   .....: 

In [254]: cal = ExampleCalendar()

In [255]: cal.holidays(datetime.datetime(2012, 1, 1), datetime.datetime(2012, 12, 31))
Out[255]: DatetimeIndex(['2012-05-28', '2012-07-04', '2012-10-08'], dtype='datetime64[ns]', freq=None)

注意:weekday=MO(2)2 * Week(weekday=2) 相同。

用这个日历创建索引,或计算偏移量,将跳过周末与假日(如,纪念日与国庆节)。下列代码用 ExampleCalendar 设定自定义工作日偏移量。至于其它偏移量,可以用于创建 DatetimeIndex 或添加到 datetimeTimestamp 对象。

In [256]: pd.date_range(start='7/1/2012', end='7/10/2012',
   .....:               freq=pd.offsets.CDay(calendar=cal)).to_pydatetime()
   .....: 
Out[256]: 
array([datetime.datetime(2012, 7, 2, 0, 0),
       datetime.datetime(2012, 7, 3, 0, 0),
       datetime.datetime(2012, 7, 5, 0, 0),
       datetime.datetime(2012, 7, 6, 0, 0),
       datetime.datetime(2012, 7, 9, 0, 0),
       datetime.datetime(2012, 7, 10, 0, 0)], dtype=object)

In [257]: offset = pd.offsets.CustomBusinessDay(calendar=cal)

In [258]: datetime.datetime(2012, 5, 25) + offset
Out[258]: Timestamp('2012-05-29 00:00:00')

In [259]: datetime.datetime(2012, 7, 3) + offset
Out[259]: Timestamp('2012-07-05 00:00:00')

In [260]: datetime.datetime(2012, 7, 3) + 2 * offset
Out[260]: Timestamp('2012-07-06 00:00:00')

In [261]: datetime.datetime(2012, 7, 6) + offset
Out[261]: Timestamp('2012-07-09 00:00:00')

AbstractHolidayCalendar 的类属性 start_dateend_date 定义日期范围。默认值如下:

In [262]: AbstractHolidayCalendar.start_date
Out[262]: Timestamp('1970-01-01 00:00:00')

In [263]: AbstractHolidayCalendar.end_date
Out[263]: Timestamp('2030-12-31 00:00:00')

这两个日期可以用 datetimeTimestamp字符串 修改。

In [264]: AbstractHolidayCalendar.start_date = datetime.datetime(2012, 1, 1)

In [265]: AbstractHolidayCalendar.end_date = datetime.datetime(2012, 12, 31)

In [266]: cal.holidays()
Out[266]: DatetimeIndex(['2012-05-28', '2012-07-04', '2012-10-08'], dtype='datetime64[ns]', freq=None)

get_calender 函数通过日历名称访问日历,返回的是日历实例。任意导入的日历都自动适用于此函数。同时,HolidayCalendarFactory 还提供了一个创建日历组合或含附加规则日历的简易接口。

In [267]: from pandas.tseries.holiday import get_calendar, HolidayCalendarFactory,\
   .....:     USLaborDay
   .....: 

In [268]: cal = get_calendar('ExampleCalendar')

In [269]: cal.rules
Out[269]: 
[Holiday: Memorial Day (month=5, day=31, offset=<DateOffset: weekday=MO(-1)>),
 Holiday: July 4th (month=7, day=4, observance=<function nearest_workday at 0x7f2460862c20>),
 Holiday: Columbus Day (month=10, day=1, offset=<DateOffset: weekday=MO(+2)>)]

In [270]: new_cal = HolidayCalendarFactory('NewExampleCalendar', cal, USLaborDay)

In [271]: new_cal.rules
Out[271]: 
[Holiday: Labor Day (month=9, day=1, offset=<DateOffset: weekday=MO(+1)>),
 Holiday: Memorial Day (month=5, day=31, offset=<DateOffset: weekday=MO(-1)>),
 Holiday: July 4th (month=7, day=4, observance=<function nearest_workday at 0x7f2460862c20>),
 Holiday: Columbus Day (month=10, day=1, offset=<DateOffset: weekday=MO(+2)>)]

------------------- End -------------------

往期精彩文章推荐:

欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持

想加入Python学习群请在后台回复【入群

万水千山总是情,点个【在看】行不行

/今日留言主题/

随便说一两句吧~

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Pandas 中,可以使用加减法运算符(+、-)对时间序列进行加减运算。还可以使用 `pd.DateOffset` 或 `pd.Timedelta` 对时间序列进行偏移。 示例: ``` python import pandas as pd # 创建时间序列 date_rng = pd.date_range(start='1/1/2020', end='1/10/2020', freq='D') df = pd.DataFrame(date_rng, columns=['date']) # 加法运算 df['plus_2_days'] = df['date'] + pd.DateOffset(days=2) # 减法运算 df['minus_2_days'] = df['date'] - pd.Timedelta(days=2) print(df) ``` 运行结果: ``` date plus_2_days minus_2_days 0 2020-01-01 2020-01-03 2019-12-30 1 2020-01-02 2020-01-04 2019-12-31 2 2020-01-03 2020-01-05 2020-01-01 3 2020-01-04 2020-01-06 2020-01-02 4 2020-01-05 2020-01-07 2020-01-03 5 2020-01-06 2020-01-08 2020-01-04 6 2020-01-07 2020-01-09 2020-01-05 7 2020-01-08 2020-01-10 2020-01-06 8 2020-01-09 2020-01-11 2020-01-07 9 2020-01-10 2020-01-12 2020-01-08 ``` 注意:如果你的时间序列是以时间戳格式存储的,需要先将其转换为日期格式。可以使用 `pd.to_datetime()` 函数进行转换。 ### 回答2: pandas时间序列可通过使用datetime或Timestamp对象进行加减法操作。下面是一些常用的方法: 1. 时间戳相减:可以通过将一个时间戳减去另一个时间戳来计算它们之间的时间差。例如,如果有两个时间戳t1和t2,可以使用t2 - t1来计算两者之间的时间差。 2. 时间间隔加减:可以使用pd.Timedelta对象来表示一个时间间隔,并将其添加到或从时间戳或时间序列中减去。例如,如果有一个时间戳t和一个时间间隔td,可以使用t + td来获得t之后td个时间间隔的时间戳。 3. 时间序列加减:可以通过将一个时间序列与一个时间间隔进行加减法操作来移动时间序列中的所有时间戳。例如,如果有一个时间序列ts和一个时间间隔td,可以使用ts + td来得到一个新的时间序列,其中所有时间戳都比原来的时间戳向后移动了td个时间间隔。 需要注意的是,时间序列的加减法操作并不会修改原始的时间序列,而是生成一个新的时间序列。此外,pandas还提供了许多其他与时间序列相关的功能和方法,如日期范围生成、时间戳转换、时间重采样等,使用这些方法可以更方便地处理和分析时间序列数据。 ### 回答3: 在pandas中,我们可以使用时间序列进行日期的加减法运算。 首先,我们需要使用pandas的to_datetime()函数将字符串转换为日期格式。然后,我们可以对这些日期进行加减运算。 例如,我们有一个时间序列data,包含日期和对应的数值。我们可以使用data['日期']来访问日期这一列。 要进行加法运算,我们可以使用data['日期'] + pd.DateOffset(days=5),这会将日期列的每个元素都增加5天。 同样地,要进行减法运算,我们可以使用data['日期'] - pd.DateOffset(days=10),这会将日期列的每个元素都减少10天。 除了days参数,我们还可以使用weeks、months、years等参数来进行不同的时间偏移。 例如,data['日期'] + pd.DateOffset(months=3)会将日期列的每个元素增加3个月。 在进行日期运算时,pandas会自动处理闰年和月底等特殊情况,确保计算的准确性。 总之,pandas时间序列提供了方便的加减法运算,可以轻松进行日期的偏移和计算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值