zoukankan      html  css  js  c++  java
  • 数据分析三剑客之Pandas时间序列

    一、时间模块:datetime

    datetime模块,主要掌握:datetime.date(), datetime.datetime(), datetime.timedelta(),日期解析方法:parser.parse

    1.datetime.date:date对象

    import datetime  # 也可以写 from datetime import date
    
    today = datetime.date.today()
    print(today,type(today))
    print(str(today),type(str(today)))
    # datetime.date.today 返回今日
    # 输出格式为 date类
    
    t = datetime.date(2016,6,1)
    print(t)
    # (年,月,日) → 直接得到当时日期

    2.datetime.datetime:datetime对象

    now = datetime.datetime.now()
    print(now,type(now))
    print(str(now),type(str(now))) 
    # .now()方法,输出当前时间
    # 输出格式为 datetime类
    # 可通过str()转化为字符串
    
    t1 = datetime.datetime(2016,6,1)
    t2 = datetime.datetime(2014,1,1,12,44,33)
    print(t1,t2)
    # (年,月,日,时,分,秒),至少输入年月日
    
    t2-t1
    # 相减得到时间差 —— timedelta

    3.datetime.timedelta:时间差

    today = datetime.datetime.today()  # datetime.datetime也有today()方法
    yestoday = today - datetime.timedelta(1)  # 
    print(today)
    print(yestoday)
    print(today - datetime.timedelta(7))
    # 时间差主要用作时间的加减法,相当于可被识别的时间“差值”

    4.parser.parse:日期字符串转换

    from dateutil.parser import parse
    
    date = '12-21-2017'
    t = parse(date)
    print(t,type(t))
    # 直接将str转化成datetime.datetime
    
    print(parse('2000-1-1'),'
    ',
         parse('5/1/2014'),'
    ',
         parse('5/1/2014', dayfirst = True),'
    ',  # 国际通用格式中,日在月之前,可以通过dayfirst来设置
         parse('22/1/2014'),'
    ',
         parse('Jan 31, 1997 10:45 PM'))
    # 各种格式可以解析,但无法支持中文

    二、Pandas时刻数据:Timestamp

    时刻数据代表时间点,是pandas的数据类型,是将值与时间点相关联的最基本类型的时间序列数据:pandas.Timestamp()

    1.pd.Timestamp()

    import numpy as np
    import pandas as pd
    
    date1 = datetime.datetime(2016,12,1,12,45,30)  # 创建一个datetime.datetime
    date2 = '2017-12-21'  # 创建一个字符串
    t1 = pd.Timestamp(date1)
    t2 = pd.Timestamp(date2)
    print(t1,type(t1))
    print(t2)
    print(pd.Timestamp('2017-12-21 15:00:22'))
    # 直接生成pandas的时刻数据 → 时间戳
    # 数据类型为 pandas的Timestamp

    2.pd.to_datetime

    from datetime import datetime
    
    date1 = datetime(2016,12,1,12,45,30)
    date2 = '2017-12-21'
    t1 = pd.to_datetime(date1)
    t2 = pd.to_datetime(date2)
    print(t1,type(t1))
    print(t2,type(t2))
    # pd.to_datetime():如果是单个时间数据,转换成pandas的时刻数据,数据类型为Timestamp
    
    lst_date = [ '2017-12-21', '2017-12-22', '2017-12-23']
    t3 = pd.to_datetime(lst_date)
    print(t3,type(t3))
    # 多个时间数据,将会转换为pandas的DatetimeIndex

    3.pd.to_datetime → 多个时间数据转换时间戳索引

    date1 = [datetime(2015,6,1),datetime(2015,7,1),datetime(2015,8,1),datetime(2015,9,1),datetime(2015,10,1)]
    date2 = ['2017-2-1','2017-2-2','2017-2-3','2017-2-4','2017-2-5','2017-2-6']
    print(date1)
    print(date2)
    t1 = pd.to_datetime(date2)
    t2 = pd.to_datetime(date2)
    print(t1)
    print(t2)
    # 多个时间数据转换为 DatetimeIndex
    
    date3 = ['2017-2-1','2017-2-2','2017-2-3','hello world!','2017-2-5','2017-2-6']
    t3 = pd.to_datetime(date3, errors = 'ignore')
    print(t3,type(t3))
    # 当一组时间序列中夹杂其他格式数据,可用errors参数返回
    # errors = 'ignore':不可解析时返回原始输入,这里就是直接生成一般数组
    
    t4 = pd.to_datetime(date3, errors = 'coerce')
    print(t4,type(t4))
    # errors = 'coerce':不可扩展,缺失值返回NaT(Not a Time),结果认为DatetimeIndex

    三、Pandas时间戳索引:DatetimeIndex

    核心:pd.date_range()

    1.pd.DatetimeIndex()与TimeSeries时间序列

    rng = pd.DatetimeIndex(['12/1/2017','12/2/2017','12/3/2017','12/4/2017','12/5/2017'])
    print(rng,type(rng))
    print(rng[0],type(rng[0]))
    # 直接生成时间戳索引,支持str、datetime.datetime
    # 单个时间戳为Timestamp,多个时间戳为DatetimeIndex
    
    st = pd.Series(np.random.rand(len(rng)), index = rng)
    print(st,type(st))
    print(st.index)
    # 以DatetimeIndex为index的Series,为TimeSries,时间序列

    2.pd.date_range()-日期范围:生成日期范围

    # 2种生成方式:①start + end; ②start/end + periods
    # 默认频率:day
    
    rng1 = pd.date_range('1/1/2017','1/10/2017', normalize=True)
    rng2 = pd.date_range(start = '1/1/2017', periods = 10)
    rng3 = pd.date_range(end = '1/30/2017 15:00:00', periods = 10)  # 增加了时、分、秒
    print(rng1,type(rng1))
    print(rng2)
    print(rng3)
    print('-------')
    # 直接生成DatetimeIndex
    # pd.date_range(start=None, end=None, periods=None, freq='D', tz=None, normalize=False, name=None, closed=None, **kwargs)
    # start:开始时间
    # end:结束时间
    # periods:偏移量
    # freq:频率,默认天,pd.date_range()默认频率为日历日,pd.bdate_range()默认频率为工作日
    # tz:时区
    
    rng4 = pd.date_range(start = '1/1/2017 15:30', periods = 10, name = 'hello world!', normalize = True)
    print(rng4)
    print('-------')
    # normalize:时间参数值正则化到午夜时间戳(这里最后就直接变成0:00:00,并不是15:30:00)
    # name:索引对象名称
    
    print(pd.date_range('20170101','20170104'))  # 20170101也可读取
    print(pd.date_range('20170101','20170104',closed = 'right'))
    print(pd.date_range('20170101','20170104',closed = 'left'))
    print('-------')
    # closed:默认为None的情况下,左闭右闭,left则左闭右开,right则左开右闭
    
    print(pd.bdate_range('20170101','20170107'))
    # pd.bdate_range()默认频率为工作日
    
    print(list(pd.date_range(start = '1/1/2017', periods = 10)))
    # 直接转化为list,元素为Timestamp

    3.pd.date_range()-日期范围:频率(1)

    print(pd.date_range('2017/1/1','2017/1/4'))  # 默认freq = 'D':每日历日
    print(pd.date_range('2017/1/1','2017/1/4', freq = 'B'))  # B:每工作日
    print(pd.date_range('2017/1/1','2017/1/2', freq = 'H'))  # H:每小时
    print(pd.date_range('2017/1/1 12:00','2017/1/1 12:10', freq = 'T'))  # T/MIN:每分
    print(pd.date_range('2017/1/1 12:00:00','2017/1/1 12:00:10', freq = 'S'))  # S:每秒
    print(pd.date_range('2017/1/1 12:00:00','2017/1/1 12:00:10', freq = 'L'))  # L:每毫秒(千分之一秒)
    print(pd.date_range('2017/1/1 12:00:00','2017/1/1 12:00:10', freq = 'U'))  # U:每微秒(百万分之一秒)
    
    print(pd.date_range('2017/1/1','2017/2/1', freq = 'W-MON'))  
    # W-MON:从指定星期几开始算起,每周
    # 星期几缩写:MON/TUE/WED/THU/FRI/SAT/SUN
    
    print(pd.date_range('2017/1/1','2017/5/1', freq = 'WOM-2MON'))  
    # WOM-2MON:每月的第几个星期几开始算,这里是每月第二个星期一

    4.pd.date_range()-日期范围:频率(2)

    print(pd.date_range('2017','2018', freq = 'M'))  
    print(pd.date_range('2017','2020', freq = 'Q-DEC'))  
    print(pd.date_range('2017','2020', freq = 'A-DEC')) 
    print('------')
    # M:每月最后一个日历日
    # Q-月:指定月为季度末,每个季度末最后一月的最后一个日历日
    # A-月:每年指定月份的最后一个日历日
    # 月缩写:JAN/FEB/MAR/APR/MAY/JUN/JUL/AUG/SEP/OCT/NOV/DEC
    # 所以Q-月只有三种情况:1-4-7-10,2-5-8-11,3-6-9-12
    
    print(pd.date_range('2017','2018', freq = 'BM'))  
    print(pd.date_range('2017','2020', freq = 'BQ-DEC'))  
    print(pd.date_range('2017','2020', freq = 'BA-DEC')) 
    print('------')
    # BM:每月最后一个工作日
    # BQ-月:指定月为季度末,每个季度末最后一月的最后一个工作日
    # BA-月:每年指定月份的最后一个工作日
    
    print(pd.date_range('2017','2018', freq = 'MS'))  
    print(pd.date_range('2017','2020', freq = 'QS-DEC'))  
    print(pd.date_range('2017','2020', freq = 'AS-DEC')) 
    print('------')
    # M:每月第一个日历日
    # Q-月:指定月为季度末,每个季度末最后一月的第一个日历日
    # A-月:每年指定月份的第一个日历日
    
    print(pd.date_range('2017','2018', freq = 'BMS'))  
    print(pd.date_range('2017','2020', freq = 'BQS-DEC'))  
    print(pd.date_range('2017','2020', freq = 'BAS-DEC')) 
    print('------')
    # BM:每月第一个工作日
    # BQ-月:指定月为季度末,每个季度末最后一月的第一个工作日
    # BA-月:每年指定月份的第一个工作日

    5.pd.date_range()-日期范围:复合频率

    print(pd.date_range('2017/1/1','2017/2/1', freq = '7D'))  # 7天
    print(pd.date_range('2017/1/1','2017/1/2', freq = '2h30min'))  # 2小时30分钟
    print(pd.date_range('2017','2018', freq = '2M'))  # 2月,每月最后一个日历日

    6.asfreq:时期频率转换

    ts = pd.Series(np.random.rand(4),
                  index = pd.date_range('20170101','20170104'))
    print(ts)
    print(ts.asfreq('4H',method = 'ffill'))
    # 改变频率,这里是D改为4H
    # method:插值模式,None不插值,ffill用之前值填充,bfill用之后值填充

    7.pd.date_range()-日期范围:超前/滞后数据

    ts = pd.Series(np.random.rand(4),
                  index = pd.date_range('20170101','20170104'))
    print(ts)
    
    print(ts.shift(2))
    print(ts.shift(-2))
    print('------')
    # 正数:数值后移(滞后);负数:数值前移(超前)
    
    per = ts/ts.shift(1) - 1
    print(per)
    print('------')
    # 计算变化百分比,这里计算:该时间戳与上一个时间戳相比,变化百分比
    
    print(ts.shift(2, freq = 'D'))
    print(ts.shift(2, freq = 'T'))
    # 加上freq参数:对时间戳进行位移,而不是对数值进行位移

    四、Pandas时期:Period

    核心:pd.Period()

    1.pd.Period()创建时期

    p = pd.Period('2017', freq = 'M')
    print(p, type(p))
    # 生成一个以2017-01开始,月为频率的时间构造器
    # pd.Period()参数:一个时间戳 + freq 参数 → freq 用于指明该 period 的长度,时间戳则说明该 period 在时间轴上的位置
    
    print(p + 1)
    print(p - 2)
    print(pd.Period('2012', freq = 'A-DEC') - 1)
    # 通过加减整数,将周期整体移动
    # 这里是按照 月、年 移动

    2.pd.period_range()创建时期范围

    prng = pd.period_range('1/1/2011', '1/1/2012', freq='M')
    print(prng,type(prng))
    print(prng[0],type(prng[0]))
    # 数据格式为PeriodIndex,单个数值为Period
    
    ts = pd.Series(np.random.rand(len(prng)), index = prng)
    print(ts,type(ts))
    print(ts.index)
    # 时间序列
    
    # Period('2011', freq = 'A-DEC')可以看成多个时间期的时间段中的游标
    # Timestamp表示一个时间戳,是一个时间截面;Period是一个时期,是一个时间段!!但两者作为index时区别不大

    3.asfreq:频率转换

    p = pd.Period('2017','A-DEC')
    print(p)
    print(p.asfreq('M', how = 'start'))  # 也可写 how = 's'
    print(p.asfreq('D', how = 'end'))  # 也可写 how = 'e'
    # 通过.asfreq(freq, method=None, how=None)方法转换成别的频率
    
    prng = pd.period_range('2017','2018',freq = 'M')
    ts1 = pd.Series(np.random.rand(len(prng)), index = prng)
    ts2 = pd.Series(np.random.rand(len(prng)), index = prng.asfreq('D', how = 'start'))
    print(ts1.head(),len(ts1))
    print(ts2.head(),len(ts2))
    # asfreq也可以转换TIMESeries的index

    4.时间戳与时期之间的转换:pd.to_period()、pd.to_timestamp()

    rng = pd.date_range('2017/1/1', periods = 10, freq = 'M')
    prng = pd.period_range('2017','2018', freq = 'M')
    
    ts1 = pd.Series(np.random.rand(len(rng)), index = rng)
    print(ts1.head())
    print(ts1.to_period().head())
    # 每月最后一日,转化为每月
    
    ts2 = pd.Series(np.random.rand(len(prng)), index = prng)
    print(ts2.head())
    print(ts2.to_timestamp().head())
    # 每月,转化为每月第一天

    五、时间序列 - 索引及切片

    TimeSeries是Series的一个子类,所以Series索引及数据选取方面的方法基本一样

    同时TimeSeries通过时间序列有更便捷的方法做索引和切片

    1.索引

    from datetime import datetime
    
    rng = pd.date_range('2017/1','2017/3')
    ts = pd.Series(np.random.rand(len(rng)), index = rng)
    print(ts.head())
    
    print(ts[0])
    print(ts[:2])
    print('-----')
    # 基本下标位置索引
    
    print(ts['2017/1/2'])
    print(ts['20170103'])
    print(ts['1/10/2017'])
    print(ts[datetime(2017,1,20)])
    print('-----')
    # 时间序列标签索引,支持各种时间字符串,以及datetime.datetime
    
    # 时间序列由于按照时间先后排序,故不用考虑顺序问题
    # 索引方法同样适用于Dataframe

    2.切片

    rng = pd.date_range('2017/1','2017/3',freq = '12H')
    ts = pd.Series(np.random.rand(len(rng)), index = rng)
    
    print(ts['2017/1/5':'2017/1/10'])
    print('-----')
    # 和Series按照index索引原理一样,也是末端包含
    
    print(ts['2017/2'].head())
    # 传入月,直接得到一个切片

    3.重复索引的时间序列

    dates = pd.DatetimeIndex(['1/1/2015','1/2/2015','1/3/2015','1/4/2015','1/1/2015','1/2/2015'])
    ts = pd.Series(np.random.rand(6), index = dates)
    print(ts)
    print(ts.is_unique,ts.index.is_unique)
    print('-----')
    # index有重复,is_unique检查 → values唯一,index不唯一
    
    print(ts['20150101'],type(ts['20150101']))
    print(ts['20150104'],type(ts['20150104']))
    print('-----')
    # index有重复的将返回多个值
    
    print(ts.groupby(level = 0).mean())
    # 通过groupby做分组,重复的值这里用平均值处理

    六、时间序列 - 重采样

    将时间序列从一个频率转换为另一个频率的过程,且会有数据的结合

    降采样:高频数据 → 低频数据,eg.以天为频率的数据转为以月为频率的数据
    升采样:低频数据 → 高频数据,eg.以年为频率的数据转为以月为频率的数据

    1.

  • 相关阅读:
    [P4721] 【模板】分治 FFT
    [GYM102452E] Erasing Numbers
    [LOJ6220] sum
    [CF776B] Sherlock and His Girlfriend
    [LOJ6087] 毒瘤题
    [LOJ2612] 花匠
    [LOJ529] 自然语言
    [CTSC2017] 吉夫特
    [LOJ6671] EntropyIncreaser 与 Minecraft
    [LOJ3196] 挂架
  • 原文地址:https://www.cnblogs.com/lee-xingxing/p/13235291.html
Copyright © 2011-2022 走看看