赞
踩
参考书目:《深入浅出Pandas:利用Python进行数据处理与分析》
pandas的索引可以用时间来替代,然后基于时间序列数据会有很多用法,了解一下。
时间对象有:
还是先导入包:
- import numpy as np
- import pandas as pd
- import datetime
#创建时间索引
pd里面的对象,或者字符串,np对象,和Python的datetime对象都可以直接创建时间索引。
pd.to_datetime(['11/1/2020',np.datetime64('2020-11-02'),datetime.datetime(2020,11,3)])
date_range创建一组时间,即时间序列
- #默认频率为天
- pd.date_range('2020-01-01',periods=10)
- pd.date_range('2020-01-01','2020-01-10') #同上
- pd.date_range(end='2020-01-10',periods=10)#同上
- pd.date_range('2022-01-01', periods=3, freq='H')#频率为小时
#跳过星期六天
pd.bdate_range('2020-11-1',periods=10)
#通常时间序列数据作为 Series 或 DataFrame 的索引,以方便对时间数据进行操作。
- # 指定开始时间和频率,周期数
- pd.Series(range(3), index=pd.date_range('2000', freq='D', periods=3))
和其他种类数据一样,时间序列也是可以用[],.loc[]方法进行切片选取数据的。
生成案例数据
- rng = pd.date_range('1/1/2021', '12/1/2021', freq='BM')
- ts = pd.Series(np.random.randn(len(rng)), index=rng)
- ts
#时间索引切片
- #DatetimeIndex 作为时间索引,同样也支持数据切片:
- ts[2:4]
ts[0:4].index #ts[::2].index
#还支持传入时间字符和各种时间对象
- ts['2021'] #z只筛选2021年的
- ts['1/29/2021']#查询这一天的值
- ts['2021-1-29']#同上
- ts['20210129'] #同上
-
- ts[datetime.datetime(2021, 9, 30):]
- ts[pd.Timestamp(2021,9,30)]
- ts[pd.Timestamp('2021-9-30')]
- ts[np.datetime64('2021-9-30')]
#也可以使用部分字符查询一定范围的数据:
- ts['2021'] # 查询整个2021年的
- ts['2021-6'] # 查询 2021年6月的
- ts['2021-6':'2021-10'] # 6月到10月的
- dft['2013-1':'2013-2-28 00:00:00'] # 精确时间
- dft['2013-1-15':'2013-1-15 12:30:00']
- dft2.loc['2013-01-05']
#由于时间格式样式比较多,很多情况下 Padnas 并不能自动识别为时间类型,所以我们在处理前的数据清洗过程中,需要专门对数据进行时间类型转换。
#astype 是最简单的时间转换方法,它只能针对相对标准的时间格式,如:
- s = pd.Series(['2016-01-31', '2016-02-29', '2016-03-31'])
- s.astype('datetime64[ns]')
#修改频率
s.astype('datetime64[D]')
pd.to_datetime(s)
#在上文中,我们转换时间时使用的是 ns (纳秒),最大程度地保留了最细的时间颗粒的供我们未来使用,但有时间我们不需要这么精确的细小粒度,如何操作呢?这就需要在 datetime64 后的括号里指定我们想要的粒度,如:
- # 一个时间文本序列
- s = pd.Series(['2016-01-31 10:18:04', '2016-02-29 12:18:09'])
- s
- '''
- 0 2016-01-31 10:18:04
- 1 2016-02-29 12:18:09
- dtype: object
- '''
- # 纳秒级
- s.astype('datetime64[ns]')
- '''
- 0 2016-01-31 10:18:04
- 1 2016-02-29 12:18:09
- dtype: datetime64[ns]
- '''
- # 日级
- s.astype('datetime64[D]')
- '''
- 0 2016-01-31
- 1 2016-02-29
- dtype: datetime64[ns]
- '''
- # 小时级
- s.astype('datetime64[h]')
- '''
- 0 2016-01-31 10:00:00
- 1 2016-02-29 12:00:00
- dtype: datetime64[ns]
- '''
- # 秒级
- s.astype('datetime64[s]')
- '''
- 0 2016-01-31 10:18:04
- 1 2016-02-29 12:18:09
- dtype: datetime64[ns]
- '''
- # 月级,当月第一天
- s.astype('datetime64[M]')
- '''
- 0 2016-01-01
- 1 2016-02-01
- dtype: datetime64[ns]
- '''
- # 年级,当年第一天
- s.astype('datetime64[Y]')
- '''
- 0 2016-01-01
- 1 2016-01-01
- dtype: datetime64[ns]
- '''
- # 周级,当周周四(原因如下)
- s.astype('datetime64[W]')
- '''
- 0 2016-01-28
- 1 2016-02-25
- dtype: datetime64[ns]
- '''

'datetime64[W]' 的结果为周四是因为这只是四舍五入,是经过设计的。括号里还可以为 2W、7D等开工,如 7D 的意思是“自纪元(1970-01-01T00:00Z )以来7D的倍数”,就像 D 的意思是“自纪元以来一天的倍数”,7D 和 W 是同义词。
我们可以看到,除了周、月、年等,其他粒度仍然以纳秒存储,不过精确度都会损失。这个规划在下边我们介绍的 pd.to_datetime() 中也适用。
#Pandas 提供的 pd.to_datetime() 是识别转换时间的主要工具。接下来看一些例子。
#从 DataFrame 的多个列中组合一个日期时间。 键可以是常见的缩写,例如['year','month','day','minute','second','ms','us','ns']): 必须: year, month, day 可选: hour, minute, second, millisecond, microsecond, nanosecond
- df = pd.DataFrame({'year': [2015, 2016],
- 'month': [2, 3],
- 'day': [4, 5]})
- df
- pd.to_datetime(df)
- pd.to_datetime(df[['year', 'month', 'day']]) # 同上
#对Series智能解析时间:
pd.to_datetime(pd.Series(['Jul 31, 2009', '2010-01-10', None]))
#列表也可以智能
- pd.to_datetime(['2005/11/23', '2010.12.31'])
- # DatetimeIndex(['2005-11-23', '2010-12-31'], dtype='datetime64[ns]', freq=None)
-
- pd.to_datetime(['04-01-2012 10:00'], dayfirst=True) # 日期在前
- # DatetimeIndex(['2012-01-04 10:00:00'], dtype='datetime64[ns]', freq=None)
- #pd.DatetimeIndex 也可以转换:
- pd.DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'])
- # DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns]', freq=None)
-
- pd.DatetimeIndex(['20180101', '20180103', '20180105'], freq='infer') #自动推断频率
- # DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns
#可以使用 pd.Timestamp() 进行转换单个时间点
- pd.to_datetime('2010/11/12')
- # Timestamp('2010-11-12 00:00:00')
-
- pd.Timestamp('2020/11/12')
- # Timestamp('2020-11-12 00:00:00')
#不规则格式转化时间
pd.to_datetime('2020_11_12',format='%Y_%m_%d',errors='ignore')
pd.to_datetime('20200101', format='%Y%m%d', errors='ignore')
# 可以让系统自己推断时间格式
pd.to_datetime('20200101', infer_datetime_format=True, errors='ignore')
- # coerce 将不会忽略错误,返回空值
- pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')
# 有时间需要字段转为字符,再转为时间
- pd.to_datetime(df.d.astype(str), format='%m/%d/%Y')
-
- # 其他
- pd.to_datetime('2010/11/12', format='%Y/%m/%d')
- # Timestamp('2010-11-12 00:00:00')
-
- pd.to_datetime('12-11-2010 00:00', format='%d-%m-%Y %H:%M')
- # Timestamp('2010-11-12 00:00:00')
-
- #对时间戳进行转换,需要给出时间单位,一般为秒:
- pd.to_datetime(1490195805, unit='s')
- # Timestamp('2017-03-22 15:16:45')
- pd.to_datetime(1490195805433502912, unit='ns')
- # Timestamp('2017-03-22 15:16:45.433502912')
-
- #对周期数据(数字列表)进行转换:
- pd.to_datetime([1, 2, 3], unit='D',origin=pd.Timestamp('1960-01-01'))
- # DatetimeIndex(['1960-01-02', '1960-01-03', '1960-01-04'], dtype='datetime64[ns]', fre

有时候不想要时间后面的小时,可以这样转化
pd.date_range('2022-1-1 00:10:00','2022-8-6 00:10:00').floor(freq='D') #忽略小时
上面的时间粒度方法也可以转化
- s=pd.Series(pd.date_range('2022-1-1','2022-8-6')).astype('datetime64[M]')
- pd.to_datetime(s.astype(str),format='%Y-%m') #实在不行字符串切。。
如果不想要20222-08-01后面的-01,可以用字符串去切,然后再变成时间。。
- def time_t(time):
- t=time.split('-')
- return t[0]+'-'+t[1]
- pd.to_datetime(s.astype('str').apply(time_t))
#对于时间序列数据,可以使用 s.dt.xxx 的形式来访问它们的属性和调用它们的方法
- s = pd.Series(pd.date_range('2020-01-01', periods=3, freq='d'))
- s.dt.date
- s.dt.time
- s.dt.timetz
- s.dt.year
- s.dt.month
- s.dt.day
- s.dt.hour
- s.dt.minute
- s.dt.second
- s.dt.microsecond
- s.dt.nanosecond
-
- #周月年相关
- s.dt.week
- s.dt.weekofyear
- s.dt.dayofweek
- s.dt.weekday
- s.dt.dayofyear #一年中第几天
- s.dt.quarter #季度数
- s.dt.is_month_start #是否月第一天
- s.dt.is_month_end #是否最后一天
- s.dt.is_quarter_start#是否季度第一天
- s.dt.is_quarter_end #是否季度最后一天
- s.dt.is_year_start #是否年第一天
- s.dt.is_year_end #是否年最后一天
- s.dt.is_leap_year #是否闰年
- s.dt.daysinmonth #当月多少天
- s.dt.days_in_month #同上
- s.dt.tz #时区
- s.dt.freq #频率
-
- #转化方法
- s.dt.to_period
- s.dt.to_pydatetime
- s.dt.tz_localize
- s.dt.tz_convert
- s.dt.normalize
- s.dt.strftime
-
- s.dt.round(fred='D')#类似四舍五入
- s.dt.floor(fred='D')#向下舍入为天
- s.dt.ceil(fred='D') #向上舍入为天
-
- s.dt.month_name #月份名称
- s.dt.day_name #星期几名称
- s.dt.qyear
- s.dt.start_time #开始时间
- s.dt.end_time #结束时间
- s.dt.days #天数
- s.dt.seconds #秒
- s.dt.microseconds #毫秒
- s.dt.nanoseconds #纳秒
- s.dt.components #时间成分
- s.dt.to_pytimedelta #转为py时间
- s.dt.total_seconds #总秒数

#可能需要将时间序列中的值在时间上前后移动或滞后。 shift() 方法也可以在时序对象上使用。
- index = pd.date_range('2020-06-01', '2020-06-03')
- ts = pd.Series(range(len(rng)), index=index)
- ts
ts.shift(-1)
ts.shift(-1,freq='B')
有时候需要将低频率数据改为高频数据
- #更改频率的主要功能是 asfreq() 方法。
- dr = pd.date_range('1/1/2022', periods=3, freq=3 * pd.offsets.BDay())
- ts = pd.Series(np.random.randn(3), index=dr)
- ts
日期频率
ts.asfreq(pd.offsets.BDay())
半天频率
ts.asfreq(pd.offsets.Hour(12))
#asfreq 提供了更多便利,因此您可以为频率转换后可能出现的任何间隙指定插值方法。
ts.asfreq(pd.offsets.BDay(), method='pad') #扩展填充
- # 对空值进行固定值填充
- ts.asfreq(freq='12h', fill_value=9.0)
#以使用几个选项之一({None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’})来填写缺失值。
#例如,要反向传播最后一个有效值以填充NaN值,请将 bfill 作为参数传递给method关键字。
ts.reindex(pd.date_range('2022-1-1', periods=15, freq='D'), method='ffill')
可以看到有效的将三个数据扩充到更多的额时间天上,并且值填充保持不变。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。