• Pandas数据分析22——pandas时间序列


     参考书目:《深入浅出Pandas:利用Python进行数据处理与分析》


    pandas的索引可以用时间来替代,然后基于时间序列数据会有很多用法,了解一下。

    时间对象有:

    还是先导入包:

    1. import numpy as np
    2. import pandas as pd
    3. import datetime

    时序索引

    #创建时间索引

    pd里面的对象,或者字符串,np对象,和Python的datetime对象都可以直接创建时间索引。

    pd.to_datetime(['11/1/2020',np.datetime64('2020-11-02'),datetime.datetime(2020,11,3)])

     date_range创建一组时间,即时间序列

    1. #默认频率为天
    2. pd.date_range('2020-01-01',periods=10)
    3. pd.date_range('2020-01-01','2020-01-10') #同上
    4. pd.date_range(end='2020-01-10',periods=10)#同上
    5. pd.date_range('2022-01-01', periods=3, freq='H')#频率为小时

     #跳过星期六天

    pd.bdate_range('2020-11-1',periods=10)

     #通常时间序列数据作为 Series 或 DataFrame 的索引,以方便对时间数据进行操作。

    1. # 指定开始时间和频率,周期数
    2. pd.Series(range(3), index=pd.date_range('2000', freq='D', periods=3))


    索引访问

    和其他种类数据一样,时间序列也是可以用[],.loc[]方法进行切片选取数据的。

    生成案例数据

    1. rng = pd.date_range('1/1/2021', '12/1/2021', freq='BM')
    2. ts = pd.Series(np.random.randn(len(rng)), index=rng)
    3. ts

    #时间索引切片 

    1. #DatetimeIndex 作为时间索引,同样也支持数据切片:
    2. ts[2:4]

    ts[0:4].index  #ts[::2].index

    #还支持传入时间字符和各种时间对象 

    1. ts['2021'] #z只筛选2021年的
    2. ts['1/29/2021']#查询这一天的值
    3. ts['2021-1-29']#同上
    4. ts['20210129'] #同上
    5. ts[datetime.datetime(2021, 9, 30):]
    6. ts[pd.Timestamp(2021,9,30)]
    7. ts[pd.Timestamp('2021-9-30')]
    8. ts[np.datetime64('2021-9-30')]

     #也可以使用部分字符查询一定范围的数据:

    1. ts['2021'] # 查询整个2021年的
    2. ts['2021-6'] # 查询 2021年6月的
    3. ts['2021-6':'2021-10'] # 6月到10月的
    4. dft['2013-1':'2013-2-28 00:00:00'] # 精确时间
    5. dft['2013-1-15':'2013-1-15 12:30:00']
    6. dft2.loc['2013-01-05']

    类型转化


    #由于时间格式样式比较多,很多情况下 Padnas 并不能自动识别为时间类型,所以我们在处理前的数据清洗过程中,需要专门对数据进行时间类型转换。
    #astype 是最简单的时间转换方法,它只能针对相对标准的时间格式,如:

    1. s = pd.Series(['2016-01-31', '2016-02-29', '2016-03-31'])
    2. s.astype('datetime64[ns]')

    #修改频率

    s.astype('datetime64[D]')

    pd.to_datetime(s)


    #转为不同时间粒度

    #在上文中,我们转换时间时使用的是 ns (纳秒),最大程度地保留了最细的时间颗粒的供我们未来使用,但有时间我们不需要这么精确的细小粒度,如何操作呢?这就需要在 datetime64 后的括号里指定我们想要的粒度,如:

    1. # 一个时间文本序列
    2. s = pd.Series(['2016-01-31 10:18:04', '2016-02-29 12:18:09'])
    3. s
    4. '''
    5. 0 2016-01-31 10:18:04
    6. 1 2016-02-29 12:18:09
    7. dtype: object
    8. '''
    9. # 纳秒级
    10. s.astype('datetime64[ns]')
    11. '''
    12. 0 2016-01-31 10:18:04
    13. 1 2016-02-29 12:18:09
    14. dtype: datetime64[ns]
    15. '''
    16. # 日级
    17. s.astype('datetime64[D]')
    18. '''
    19. 0 2016-01-31
    20. 1 2016-02-29
    21. dtype: datetime64[ns]
    22. '''
    23. # 小时级
    24. s.astype('datetime64[h]')
    25. '''
    26. 0 2016-01-31 10:00:00
    27. 1 2016-02-29 12:00:00
    28. dtype: datetime64[ns]
    29. '''
    30. # 秒级
    31. s.astype('datetime64[s]')
    32. '''
    33. 0 2016-01-31 10:18:04
    34. 1 2016-02-29 12:18:09
    35. dtype: datetime64[ns]
    36. '''
    37. # 月级,当月第一天
    38. s.astype('datetime64[M]')
    39. '''
    40. 0 2016-01-01
    41. 1 2016-02-01
    42. dtype: datetime64[ns]
    43. '''
    44. # 年级,当年第一天
    45. s.astype('datetime64[Y]')
    46. '''
    47. 0 2016-01-01
    48. 1 2016-01-01
    49. dtype: datetime64[ns]
    50. '''
    51. # 周级,当周周四(原因如下)
    52. s.astype('datetime64[W]')
    53. '''
    54. 0 2016-01-28
    55. 1 2016-02-25
    56. dtype: datetime64[ns]
    57. '''

    'datetime64[W]' 的结果为周四是因为这只是四舍五入,是经过设计的。括号里还可以为 2W、7D等开工,如 7D 的意思是“自纪元(1970-01-01T00:00Z )以来7D的倍数”,就像 D 的意思是“自纪元以来一天的倍数”,7D 和 W 是同义词。

    我们可以看到,除了周、月、年等,其他粒度仍然以纳秒存储,不过精确度都会损失。这个规划在下边我们介绍的 pd.to_datetime() 中也适用。


    转为时间 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

    1. df = pd.DataFrame({'year': [2015, 2016],
    2. 'month': [2, 3],
    3. 'day': [4, 5]})
    4. df

    1. pd.to_datetime(df)
    2. pd.to_datetime(df[['year', 'month', 'day']]) # 同上

     #对Series智能解析时间:

    pd.to_datetime(pd.Series(['Jul 31, 2009', '2010-01-10', None]))

     #列表也可以智能

    1. pd.to_datetime(['2005/11/23', '2010.12.31'])
    2. # DatetimeIndex(['2005-11-23', '2010-12-31'], dtype='datetime64[ns]', freq=None)
    3. pd.to_datetime(['04-01-2012 10:00'], dayfirst=True) # 日期在前
    4. # DatetimeIndex(['2012-01-04 10:00:00'], dtype='datetime64[ns]', freq=None)
    1. #pd.DatetimeIndex 也可以转换:
    2. pd.DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'])
    3. # DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns]', freq=None)
    4. pd.DatetimeIndex(['20180101', '20180103', '20180105'], freq='infer') #自动推断频率
    5. # DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns

     #可以使用 pd.Timestamp() 进行转换单个时间点

    1. pd.to_datetime('2010/11/12')
    2. # Timestamp('2010-11-12 00:00:00')
    3. pd.Timestamp('2020/11/12')
    4. # 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')

    1. # coerce 将不会忽略错误,返回空值
    2. pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')

    # 有时间需要字段转为字符,再转为时间

    1. pd.to_datetime(df.d.astype(str), format='%m/%d/%Y')
    2. # 其他
    3. pd.to_datetime('2010/11/12', format='%Y/%m/%d')
    4. # Timestamp('2010-11-12 00:00:00')
    5. pd.to_datetime('12-11-2010 00:00', format='%d-%m-%Y %H:%M')
    6. # Timestamp('2010-11-12 00:00:00')
    7. #对时间戳进行转换,需要给出时间单位,一般为秒:
    8. pd.to_datetime(1490195805, unit='s')
    9. # Timestamp('2017-03-22 15:16:45')
    10. pd.to_datetime(1490195805433502912, unit='ns')
    11. # Timestamp('2017-03-22 15:16:45.433502912')
    12. #对周期数据(数字列表)进行转换:
    13. pd.to_datetime([1, 2, 3], unit='D',origin=pd.Timestamp('1960-01-01'))
    14. # 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') #忽略小时

     上面的时间粒度方法也可以转化

    1. s=pd.Series(pd.date_range('2022-1-1','2022-8-6')).astype('datetime64[M]')
    2. pd.to_datetime(s.astype(str),format='%Y-%m') #实在不行字符串切。。

     如果不想要20222-08-01后面的-01,可以用字符串去切,然后再变成时间。。

    1. def time_t(time):
    2. t=time.split('-')
    3. return t[0]+'-'+t[1]
    4. pd.to_datetime(s.astype('str').apply(time_t))

     


     

    .dt 时间访问器

    #对于时间序列数据,可以使用 s.dt.xxx 的形式来访问它们的属性和调用它们的方法

    1. s = pd.Series(pd.date_range('2020-01-01', periods=3, freq='d'))
    2. s.dt.date
    3. s.dt.time
    4. s.dt.timetz
    5. s.dt.year
    6. s.dt.month
    7. s.dt.day
    8. s.dt.hour
    9. s.dt.minute
    10. s.dt.second
    11. s.dt.microsecond
    12. s.dt.nanosecond
    13. #周月年相关
    14. s.dt.week
    15. s.dt.weekofyear
    16. s.dt.dayofweek
    17. s.dt.weekday
    18. s.dt.dayofyear #一年中第几天
    19. s.dt.quarter #季度数
    20. s.dt.is_month_start #是否月第一天
    21. s.dt.is_month_end #是否最后一天
    22. s.dt.is_quarter_start#是否季度第一天
    23. s.dt.is_quarter_end #是否季度最后一天
    24. s.dt.is_year_start #是否年第一天
    25. s.dt.is_year_end #是否年最后一天
    26. s.dt.is_leap_year #是否闰年
    27. s.dt.daysinmonth #当月多少天
    28. s.dt.days_in_month #同上
    29. s.dt.tz #时区
    30. s.dt.freq #频率
    31. #转化方法
    32. s.dt.to_period
    33. s.dt.to_pydatetime
    34. s.dt.tz_localize
    35. s.dt.tz_convert
    36. s.dt.normalize
    37. s.dt.strftime
    38. s.dt.round(fred='D')#类似四舍五入
    39. s.dt.floor(fred='D')#向下舍入为天
    40. s.dt.ceil(fred='D') #向上舍入为天
    41. s.dt.month_name #月份名称
    42. s.dt.day_name #星期几名称
    43. s.dt.qyear
    44. s.dt.start_time #开始时间
    45. s.dt.end_time #结束时间
    46. s.dt.days #天数
    47. s.dt.seconds #秒
    48. s.dt.microseconds #毫秒
    49. s.dt.nanoseconds #纳秒
    50. s.dt.components #时间成分
    51. s.dt.to_pytimedelta #转为py时间
    52. s.dt.total_seconds #总秒数

    移动 Shifting

     #可能需要将时间序列中的值在时间上前后移动或滞后。 shift() 方法也可以在时序对象上使用。

    1. index = pd.date_range('2020-06-01', '2020-06-03')
    2. ts = pd.Series(range(len(rng)), index=index)
    3. ts

    ts.shift(-1)

    ts.shift(-1,freq='B')


    频率转换 asfreq()

    有时候需要将低频率数据改为高频数据

    1. #更改频率的主要功能是 asfreq() 方法。
    2. dr = pd.date_range('1/1/2022', periods=3, freq=3 * pd.offsets.BDay())
    3. ts = pd.Series(np.random.randn(3), index=dr)
    4. ts

    日期频率

    ts.asfreq(pd.offsets.BDay())

     半天频率

    ts.asfreq(pd.offsets.Hour(12))

     #asfreq 提供了更多便利,因此您可以为频率转换后可能出现的任何间隙指定插值方法。

    ts.asfreq(pd.offsets.BDay(), method='pad')  #扩展填充

    1. # 对空值进行固定值填充
    2. 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')

     可以看到有效的将三个数据扩充到更多的额时间天上,并且值填充保持不变。

  • 相关阅读:
    【剑指 Offer】62. 圆圈中最后剩下的数字
    SQL Server 入门知识
    汽车行业怎么做网络推广有效果?汽车行业怎样做线上推广?
    Ubuntu 命令行安装 nodejs 并更新
    代码随想录 | Day 53 - LeetCode 1143. 最长公共子序列、LeetCode 1035. 不相交的线、LeetCode 53. 最大子序和
    IND83081芯片介绍(一)
    强强联手,NVIDIA 与 Ampere Computing 重磅推出云原生服务器平台
    python的自定义函数的用法和实例
    (附源码)spring boot学科竞赛活动报名系统 毕业设计 012239
    【数据结构-二叉树】二叉树
  • 原文地址:https://blog.csdn.net/weixin_46277779/article/details/126269587