11.3 日期范围、频率和位移
pandas的通用时间序列是不规则的,即时间序列的频率不是固定的。在处理固定频率的场景,例如每日的,每月的或每几分钟时,pandas有一套标准的时间序列频率和工具用于重新采样、推断频率以及生成固定频率的数据范围。例如使用resample方法将样本时间序列转换为固定的每日频率数据:
dates = [datetime(2011, 1, 2), datetime(2011, 1, 5),
datetime(2011, 1, 7), datetime(2011, 1, 8),
datetime(2011, 1, 10), datetime(2011, 1, 12)]
ts = pd.Series(np.random.randn(6), index=dates)
ts
2011-01-02 -0.763339
2011-01-05 -0.596903
2011-01-07 0.081843
2011-01-08 0.500183
2011-01-10 -0.369707
2011-01-12 0.641366
dtype: float64
resampler=ts.resample('D') # D 被解释为每日频率。
resampler
<pandas.core.resample.DatetimeIndexResampler object at 0x000002177147FBC8>
在频率之间转换,又称为重新采样。这里只是展示如何使用基础频率和其倍数
11.3.1 生成日期范围
就是pandas.date_range ,用于根据特定频率生成指定长度的DatetimeIndex:
index = pd.date_range('2020-7-1','20200714')
index
DatetimeIndex(['2020-07-01', '2020-07-02', '2020-07-03', '2020-07-04',
'2020-07-05', '2020-07-06', '2020-07-07', '2020-07-08',
'2020-07-09', '2020-07-10', '2020-07-11', '2020-07-12',
'2020-07-13', '2020-07-14'],
dtype='datetime64[ns]', freq='D')
pd.date_range(start='2012-04-01', periods=2) # date_range生成的是每日的时间戳,可用仅传递一个起始或结尾日期和一个范围
DatetimeIndex(['2012-04-01', '2012-04-02'], dtype='datetime64[ns]', freq='D')
pd.date_range(end='2012-06-01', periods=2)
DatetimeIndex(['2012-05-31', '2012-06-01'], dtype='datetime64[ns]', freq='D')
# 开始日期和结束日期严格定义了生成日期索引的边界。例如需要一个包含每月最后业务日期的时间索引,可以使用BM频率,只有范围内的日期会包括
pd.date_range('2000-01-01', '2000-12-01', freq='BM')
DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-28', # 每月的最后一个工作日
'2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31',
'2000-09-29', '2000-10-31', '2000-11-30'],
dtype='datetime64[ns]', freq='BM')
讲究。。。
默认情况下,date_rane保留开始或结束时间戳的时间(如果有的话):
pd.date_range('2012-05-02 12:56:31', periods=5)
DatetimeIndex(['2012-05-02 12:56:31', '2012-05-03 12:56:31',
'2012-05-04 12:56:31', '2012-05-05 12:56:31',
'2012-05-06 12:56:31'],
dtype='datetime64[ns]', freq='D')
# 想获得包含时间信息的开始日期或结束日期,但是你想要生成的是标准化为零点的时间戳,使用normalize选项。
pd.date_range('2012-05-02 12:56:31', periods=5, normalize=True)
DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05',
'2012-05-06'], # 将开始/结束日期标准化为零点,然后在生成日期。
dtype='datetime64[ns]', freq='D')
11.3.2 频率和日期偏置
pandas中的频率是由基础频率和倍数组成 。基础频率就是 M D这些。对于每个基础频率,都有一个对象可用被用于定义日期偏置。例如每小时的频率可以使用Hour 类来表示
from pandas.tseries.offsets import Hour, Minute
hour = Hour()
hour
<Hour>
four_hour=Hour(4)
four_hour
<4 * Hours>
pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h') # 但是对于大多数不用显示的创建这些对象,而是使用
DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00', # 字符串别名,4H,在基础索引前放一个整数就表示倍数。
'2000-01-01 08:00:00', '2000-01-01 12:00:00',
'2000-01-01 16:00:00', '2000-01-01 20:00:00',
'2000-01-02 00:00:00', '2000-01-02 04:00:00',
'2000-01-02 08:00:00', '2000-01-02 12:00:00',
'2000-01-02 16:00:00', '2000-01-02 20:00:00',
'2000-01-03 00:00:00', '2000-01-03 04:00:00',
'2000-01-03 08:00:00', '2000-01-03 12:00:00',
'2000-01-03 16:00:00', '2000-01-03 20:00:00'],
dtype='datetime64[ns]', freq='4H')
Hour(2) + Minute(30) # 多个偏好设置可以进行加法联合
<150 * Minutes>
pd.date_range('2000-01-01', periods=10, freq='1h30min') # 还可以传递频率字符串,可以有效的转换为同等的表达式。
DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00',
'2000-01-01 03:00:00', '2000-01-01 04:30:00',
'2000-01-01 06:00:00', '2000-01-01 07:30:00',
'2000-01-01 09:00:00', '2000-01-01 10:30:00',
'2000-01-01 12:00:00', '2000-01-01 13:30:00'],
dtype='datetime64[ns]', freq='90T')
有些频率描述点是不均匀的,例如M BM 却决于当月的天数,这些日期称为锚定偏置量
11.3.2.1 月中某星期的日期
rng = pd.date_range('2012-01-01', '2012-09-01', freq='WOM-3FRI') # 每月第三个星期五
list(rng)
[Timestamp('2012-01-20 00:00:00', freq='WOM-3FRI'),
Timestamp('2012-02-17 00:00:00', freq='WOM-3FRI'),
Timestamp('2012-03-16 00:00:00', freq='WOM-3FRI'),
Timestamp('2012-04-20 00:00:00', freq='WOM-3FRI'),
Timestamp('2012-05-18 00:00:00', freq='WOM-3FRI'),
Timestamp('2012-06-15 00:00:00', freq='WOM-3FRI'),
Timestamp('2012-07-20 00:00:00', freq='WOM-3FRI'),
Timestamp('2012-08-17 00:00:00', freq='WOM-3FRI')]
11.3.3 位移(前向和后向)日期
位移是指将日期按时间向后向前移动。series and dateframe都有一个shift 方法来进行简单的前向和后向位移,而不改变索引:
ts = pd.Series(np.random.randn(4),
index=pd.date_range('1/1/2000', periods=4, freq='M'))
ts
2000-01-31 0.239816
2000-02-29 -0.742286
2000-03-31 -0.237450
2000-04-30 0.375140
Freq: M, dtype: float64
ts.shift(2)
2000-01-31 NaN # 这个是后移吧。。。
2000-02-29 NaN
2000-03-31 0.239816
2000-04-30 -0.742286
Freq: M, dtype: float64
ts.shift(-2)
2000-01-31 -0.23745
2000-02-29 0.37514 # 缺失位置就不上缺失值
2000-03-31 NaN
2000-04-30 NaN
Freq: M, dtype: float64
ts / ts.shift(1) - 1 # shift常用于计算时间序列或dataframe多列时间序列的百分比变化。
ts.shift(2, freq='M') # 如果频率是已知的,可以传递给shift来推移时间戳
2000-03-31 0.239816
2000-04-30 -0.742286
2000-05-31 -0.237450
2000-06-30 0.375140
Freq: M, dtype: float64
ts.shift(3, freq='D') # 这些都可以,这里的T是分钟
ts.shift(1, freq='90T')
11.3.3.1 使用偏置进行位移日期
pandas日期偏置也可以使用datetiem or Timestamp 对象完成。
from pandas.tseries.offsets import Day, MonthEnd
now = datetime(2011, 11, 17)
now + 3 * Day()
Timestamp('2011-11-20 00:00:00')
now+MonthEnd() # 添加一个锚定偏置量,比如MonthEnd,根据频率规则,第一个增量会将日期前滚到下一个日期
Timestamp('2011-11-30 00:00:00')
now+MonthEnd(2) # 啥叫前滚到下一个日期。。。反正0 1 都是11-30
Timestamp('2011-12-31 00:00:00')
offset=MonthEnd()
offset.rollforward(now)
Timestamp('2011-11-30 00:00:00') # 锚定偏置可以使用rollforward rollback分别显示的将日期前滚后滚
offset.rollback(now)
Timestamp('2011-10-31 00:00:00')
ts = pd.Series(np.random.randn(20),
index=pd.date_range('1/15/2000', periods=20, freq='4d'))
ts.groupby(offset.rollforward).mean() # 位移方法与groupby一起使用
2000-01-31 0.593707
2000-02-29 0.141409
2000-03-31 0.083633
dtype: float64
ts.resample('M').mean() # 这个方法更简单,以后再讨论。。。
2000-01-31 0.593707
2000-02-29 0.141409
2000-03-31 0.083633
Freq: M, dtype: float64