DataWhale & Pandas(时序数据)

DataWhale & Pandas(时序数据)


Pandas学习手册

写在前面:

这一个月来的pandas学习,衔接了十一月的numpy和一月份的LeetCode,本以为是普普通通的pandas学习,就简单复习一下,哎,你猜怎么着,我是万万没想到啊,之前学的那就叫认识了个名词,在DW各位助教和群里大神还有队长楠楠的帮助下,这个小菜鸟,有了飞速的成长,毫不夸张的说,这一个月所学到的东西,占到了2020年全年的六成以上,光是在群里不讲话看看他们的解题思路就能学到很多东西。当然也感谢耿老师的开源学习资料,对,就上面那个蓝色的链接(pandas学习手册),虽然今天它崩了

不过问题不大, 已经学完了(机智),最后呢感谢各位的帮助,认识大家都很开心啊,虽然这段时间我的生活过的比较坎坷,但是学习上还好是没跑偏,在这其中呢,也少不了各位的帮助和助教的鼓励。这是这期的结束,同时,也是新一年学习的开始,大家,一起加油呀!

学习大纲: 


目录

DataWhale & Pandas(时序数据)

写在前面:

学习大纲: 

时间点的创建

时序索引切片

利用strftime重新修改时间格式

普通的expanding函数于rolling(window = len(s),min_periods = 1),是对序列的累计计算

时空数据

一、时序中的基本对象

二、时间戳

1. Timestamp的构造及属性

2. Datetime序列的生成

3. dt对象

4. 时间戳的切片与索引

三、时间差

1. Timedelta的生成

2. Timedelta的运算

四、日期偏置

1. Offset对象

2. 偏置字符串

五、时序中的滑窗与分组

1. 滑动窗口

2. 重采样

六、练习

Ex1:太阳辐射数据集

Ex2:水果销量数据集


时间点的创建

  • to_datetime方法
pd.to_datetime('2021.1.1')
pd.to_datetime('2021 1.1')
pd.to_datetime('20210101')
pd.to_datetime('2021.0101')
  • 时间精度与范围限制(Timestamp的精度最小到纳秒(ns))
#时间范围
pd.Timestamp.min  #最小
pd.Timestamp.max  #最大
#精度
pd.to_datetime('2020/1/1 00:00:00.123456789')
  • date_range方法
pd.date_range(start='2021/1/1',end='2021/1/10',periods=3)  
pd.date_range(start='2021/1/1',end='2021/1/10',freq='D')
pd.date_range(start='2021/1/1',periods=3,freq='D')
pd.date_range(end='2021/1/3',periods=3,freq='D') 

#start/end/periods(时间点个数)/freq(间隔方法)

时序索引切片

  • random.randn(a)生成标准正态分布;
  • random.randn(a,b)生成a行b列的标准正态分布。
range1 = pd.date_range('2020','2021', freq='W')
tg = pd.Series(np.random.randn(len(range1)), index=range1)
tg.head()
##运行结果:
#2020-01-05   -0.275349
#2020-01-12    2.359218
#2020-01-19   -0.447633
#2020-01-26   -0.479830
#2020-02-02    0.517587
#Freq: W-SUN, dtype: float64
ts['2020-01-05']

# 0.009639339138300618

利用strftime重新修改时间格式

pd.Series(ts.index).dt.strftime('%Y*%m*%d').head()


#0    2020*01*05
#1    2020*01*12
#2    2020*01*19
#3    2020*01*26
#4    2020*02*02
#dtype: object

普通的expanding函数于rolling(window = len(s),min_periods = 1),是对序列的累计计算

s.rolling(window=len(s),min_periods=1).sum().head()

#2020-01-01    0.842824
#2020-01-02    1.668950
#2020-01-03    2.529507
#2020-01-04    3.041409
#2020-01-05    3.186310
#Freq: D, dtype: float64

s.expanding().sum().head()

#2020-01-01    0.842824
#2020-01-02    1.668950
#2020-01-03    2.529507
#2020-01-04    3.041409
#2020-01-05    3.186310
#Freq: D, dtype: float64

时空数据

import numpy as np
import pandas as pd

一、时序中的基本对象

时间序列的概念在日常生活中十分常见,但对于一个具体的时序事件而言,可以从多个时间对象的角度来描述。例如2020年9月7日周一早上8点整需要到教室上课,这个课会在当天早上10点结束,其中包含了哪些时间概念?

  • 第一,会出现时间戳(Date times)的概念,即'2020-9-7 08:00:00'和'2020-9-7 10:00:00'这两个时间点分别代表了上课和下课的时刻,在pandas中称为Timestamp。同时,一系列的时间戳可以组成DatetimeIndex,而将它放到Series中后,Series的类型就变为了datetime64[ns],如果有涉及时区则为datetime64[ns, tz],其中tz是timezone的简写。

  • 第二,会出现时间差(Time deltas)的概念,即上课需要的时间,两个Timestamp做差就得到了时间差,pandas中利用Timedelta来表示。类似的,一系列的时间差就组成了TimedeltaIndex, 而将它放到Series中后,Series的类型就变为了timedelta64[ns]

  • 第三,会出现时间段(Time spans)的概念,即在8点到10点这个区间都会持续地在上课,在pandas利用Period来表示。类似的,一系列的时间段就组成了PeriodIndex, 而将它放到Series中后,Series的类型就变为了Period

  • 第四,会出现日期偏置(Date offsets)的概念,假设你只知道9月的第一个周一早上8点要去上课,但不知道具体的日期,那么就需要一个类型来处理此类需求。再例如,想要知道2020年9月7日后的第30个工作日是哪一天,那么时间差就解决不了你的问题,从而pandas中的DateOffset就出现了。同时,pandas中没有为一列时间偏置专门设计存储类型,理由也很简单,因为需求比较奇怪,一般来说我们只需要对一批时间特征做一个统一的特殊日期偏置。

概念 单元素类型 数组类型 pandas数据类型
Date times Timestamp DatetimeIndex datetime64[ns]
Time deltas Timedelta TimedeltaIndex timedelta64[ns]
Time spans Period PeriodIndex period[freq]
Date offsets DateOffset None None

二、时间戳

1. Timestamp的构造及属性

  • 单个时间戳通过pd.Timestamp实现,一般来讲常见的日期格式能够被成功转换
  • 可以通过year,month,day,hour,min,second来获取对应的具体数值
  • 通过pd.Timestamp.maxpd.Timestamp.min可以获取时间戳表示的范围

2. Datetime序列的生成

  • 一组时间戳可以组成时间序列,可以用to_datetime和date_range来生成,to_datetime能够把一列时间戳格式的对象转换成为datetime64[ns]类型的时间序列
  • 在极少数情况,时间戳格式不满足时,可以通过强制使用format进行匹配
  • 如果是非 pandas 内部的 Series ,因此返回的是 DatetimeIndex ,如果想要转为 datetime64[ns] 的序列,需要显式用 Series 转化
  • date_range 是一种生成连续间隔时间的一种方法,其重要的参数为 start, end, freq, periods ,它们分别表示开始时间,结束时间,时间间隔,时间戳个数
  • 改变序列采样频率的方法 asfreq ,它能够根据给定的 freq 对序列进行类似于 reindex 的操作,新的Index值为缺失

3. dt对象

  • 如同category, string的序列上定义了cat, str来完成分类数据和文本数据的操作,在时序类型的序列上定义了dt对象来完成许多时间序列的相关操作。
  • 对于datetime64[ns]类型而言,可以大致分为三类操作:取出时间相关的属性、判断时间戳是否满足条件、取整操作。
  • 第一类操作的常用属性包括:date, time, year, month, day, hour, minute, second, microsecond, nanosecond, dayofweek, dayofyear, weekofyear, daysinmonth, quarter,其中daysinmonth, quarter分别表示月中的第几天和季度。
  • 经常使用的是dayofweek ,它返回了周中的星期情况,周一为0、周二为1
  • 可以通过month_name, day_name 返回英文的月名和星期名,注意它们是方法而不是属性
  • 判断时间戳是否满足条件:is_year_start,is_year_end
  • s.dt.is_year_start # 还可选 is_quarter/month_start
    
    s.dt.is_year_end # 还可选 is_quarter/month_end
  • 取整操作:取整操作包含 round, ceil, floor ,它们的公共参数为 freq ,常用的包括 H, min, S (小时、分钟、秒)

4. 时间戳的切片与索引

  • 如果想要选出某个子时间戳序列,第一类方法是利用 dt 对象和布尔条件联合使用,另一种方式是利用切片,后者常用于连续时间戳

三、时间差

1. Timedelta的生成

  • 间差可以理解为两个时间戳的差,可以通过 pd.Timedelta 来构造
  • 生成时间差序列的主要方式是 pd.to_timedelta ,其类型为 timedelta64[ns]
  • 与 date_range 一样,时间差序列也可以用 timedelta_range 来生成,它们两者具有一致的参数
  • 对于 Timedelta 序列,同样可以定义 dt 对象,dt主要定义的属性包括 days, seconds, mircroseconds, nanoseconds ,它们分别返回了对应的时间差特征。需要注意的是,这里的 seconds 不是指单纯的秒,而是对天数取余后剩余的秒数,如果想要直接得到对应的秒数total_seconds

2. Timedelta的运算

  • 与标量的乘法运算、与时间戳的加减法运算、与时间差的加减法与除法运算:

四、日期偏置

1. Offset对象

  • Offset 对象在 pd.offsets 中被定义。当使用+时获取离其最近的下一个日期,当使用-时获取离其最近的上一个日期
  • Offset中,需要介绍一个特殊的Offset对象CDay,其中的holidays, weekmask参数能够分别对自定义的日期和星期进行过滤,前者传入了需要过滤的日期列表,后者传入的是三个字母的星期缩写构成的星期字符串,其作用是只保留字符串中出现的星期

注意:不要使用部分Offset

  • 在当前版本下由于一些 bug ,不要使用 Day 级别以下的 Offset 对象,比如 Hour, Second等,请使用对应的 Timedelta 对象来代替

2. 偏置字符串

  • pandas中几乎每一个 Offset 对象绑定了日期偏置字符串( frequencies strings/offset aliases ),可以指定 Offset 对应的字符串来替代使用

注意:关于时区问题的说明

  • 各类时间对象的开发,除了使用python内置的datetime模块,pandas还利用了dateutil模块,很大一部分是为了处理时区问题。总所周知,我国是没有夏令时调整时间一说的,但有些国家会有这种做法,导致了相对而言一天里可能会有23/24/25个小时,也就是relativedelta,这使得Offset对象和Timedelta对象有了对同一问题处理产生不同结果的现象

五、时序中的滑窗与分组

1. 滑动窗口

  • 时序的滑窗函数,即把滑动窗口用 freq 关键词代替
  • 对于 shift 函数而言,作用在 datetime64 为索引的序列上时,可以指定 freq 单位进行滑动
  • datetime64[ns] 的序列进行 diff 后就能够得到 timedelta64[ns] 的序列,这能够使用户方便地观察有序时间序列的间隔

2. 重采样

  • 重采样对象resamplegroupby的用法相似。
  • 没有内置定义函数是可以用apply方法进行自定义
  • resample中要特别注意组边界值的处理情况,默认情况下起始值的计算方法是从最小值时间戳对应日期的午夜00:00:00开始增加freq,直到不超过该最小时间戳的最大时间戳,由此对应的时间戳为起始值,然后每次累加freq参数作为分割结点进行分组,区间情况为左闭右开。
  • 用户希望从序列的最小时间戳开始依次增加freq进行分组,此时可以指定origin参数为start
  • 索引一般是取组的第一个时间戳,但 M, A, Q, BM, BA, BQ, W 这七个是取对应区间的最后一个时间戳

六、练习

Ex1:太阳辐射数据集

现有一份关于太阳辐射的数据集:

df = pd.read_csv('../data/solar.csv', usecols=['Data','Time','Radiation','Temperature'])
df.head(3)

  •  将Datetime, Time合并为一个时间列Datetime,同时把它作为索引后排序。
# to_datetime将多列合并转为时间序列

每条记录时间的间隔显然并不一致,请解决如下问题:

  • 找出间隔时间的前三个最大值所对应的三组时间戳。
s = df.index.to_series().reset_index(drop=True).diff().dt.total_seconds()
max_3 = s.nlargest(3).index
df.index[max_3.union(max_3-1)]
  • 是否存在一个大致的范围,使得绝大多数的间隔时间都落在这个区间中?如果存在,请对此范围内的样本间隔秒数画出柱状图,设置bins=50
res = s.mask((s>s.quantile(0.99))|(s<s.quantile(0.01)))
_ = plt.hist(res, bins=50)

求如下指标对应的Series

  • 温度与辐射量的6小时滑动相关系数
  • 以三点、九点、十五点、二十一点为分割,该观测所在时间区间的温度均值序列
  • 每个观测6小时前的辐射量(一般而言不会恰好取到,此时取最近时间戳对应的辐射量)

Ex2:水果销量数据集

现有一份2019年每日水果销量记录表:

df = pd.read_csv('../data/fruit.csv')
df.head(3)

统计如下指标:

  • 每月上半月(15号及之前)与下半月葡萄销量的比值
  • 每月最后一天的生梨销量总和
  • 每月最后一天工作日的生梨销量总和
  • 每月最后五天的苹果销量均值
  • 按月计算周一至周日各品种水果的平均记录条数,行索引外层为水果名称,内层为月份,列索引为星期。
  • 按天计算向前10个工作日窗口的苹果销量均值序列,非工作日的值用上一个工作日的结果填充。

猜你喜欢

转载自blog.csdn.net/adminkeys/article/details/112446056