【时间序列分析】S04E03时间序列处理的核心技巧

直观地获取和组织时间数据是pandas时间序列工具最重要、最显著的特点。pandas不仅支持一些普通的索引功能,比如:合并数据时自动对齐索引,便捷的数据切片和取值操作等等,还有专门为时间序列提供的额外操作方法。

这一集我们就专门讨论pandas为时间序列操作准备的一些核心技巧。

1.时间序列的获取

金融领域是时间序列分析的主战场,而pandas起初也正是为金融数据模型服务的,因此为了便于我们学习和讨论,我们选取腾讯公司从上市之日起到今天的收盘股价数据来进行接下来的讨论分析。

利用python来获取股价数据是非常容易的一件事儿,有很多种方法,这里我们用一个第三方工具pandas_datareader,通过雅虎财经来获取相应的数据。关于什么网络爬虫之类的知识,大家不用了解,会使用API就好了,说实话这个确实太简单、太好用了。

首先我们要在命令行中利用pip3工具单独安装一下pandas_datareader,为了画图好看,我们还另外安装一个seaborn工具。

我们先看看下面这段代码,从中我们获取了腾讯的股价数据,并绘制了他的每日收盘价的曲线图。

代码片段:

from pandas_datareader import data
import matplotlib.pyplot as plt
import pandas as pd
import seaborn
seaborn.set()

stock_code = '0700.hk'
start_date = '2000-01-01'
end_date = '2019-05-01'
stock_info = data.get_data_yahoo(stock_code, start_date, end_date)
print(stock_info.head())
print(type(stock_info))

plt.plot(stock_info['Close'], 'b')
plt.show()

运行结果:

             High    Low   Open  Close        Volume  Adj Close
Date                                                           
2004-06-16  0.925  0.815  0.875  0.830  2.198875e+09   0.749649
2004-06-17  0.875  0.825  0.830  0.845  4.190075e+08   0.763197
2004-06-18  0.850  0.790  0.840  0.805  1.829900e+08   0.727070
2004-06-21  0.825  0.790  0.820  0.800  1.140850e+08   0.722554
2004-06-23  0.890  0.805  0.810  0.885  2.750800e+08   0.799325

<class 'pandas.core.frame.DataFrame'>

绘制出来的曲线图

在这段程序当中,涉及的内容还不少,我们简单的解读一下:

首先我们指定了腾讯公司的股票代码和要查看的起止时间字符串,利用pandas_datareader模块中的data对象所提供的API:get_data_yahoo,就轻松的从雅虎财经中获取了股票数据。

返回的对象是一个dataframe数据类型,数据列中包含了高、开、低、收等数据,我们只关心收盘价数据,因此专门挑出这一列的时间序列数据,绘制了曲线图。

程序中,我们尝试使用seaborn来优化原始matplotlib的绘图效果,当然这里只用了seaborn.set()这一句代码,大家知道就好,也不不必过多深究。接下来我们的操作都基于腾讯公司历史收盘价的时间序列展开。

2.重采样和频率转换

在处理时间序列的时候,我们并不一定会去仔细关心每一个时间点的数据,一般而言会着重关心一些有代表性或者说有某种意义的时间节点。这样就涉及到了重采样的概念,也就是说在原始时间序列上,按照我们指定的新的频率进行数据采样,提取出我们关心的时间节点以及对应的数据值。

这里涉及到pandas中的两种方法:resampleasfreq,虽然都是关于解决频率采样的问题,但是他们有明显的不同。

resample是以数据累计为基础,他获取的不是指定频率下某个时间点的数值,而是整个重采样频率周期内的统计值(均值、和等等)。

而asfreq则不同,他就很直接,就是强调数据的选择,他获取的就是指定频率下具体时间点对应的数值。

说了这么多,比较空洞,我们还是看例子说话:

代码片段:

from pandas_datareader import data
import matplotlib.pyplot as plt
import pandas as pd
import seaborn
seaborn.set()

stock_code = '0700.hk'
start_date = '2000-01-01'
end_date = '2019-05-01'
stock_info = data.get_data_yahoo(stock_code, start_date, end_date)
print(stock_info.head())
print(type(stock_info))

stock_info['Close'].plot(color='b', alpha=0.5, style='-')
stock_info['Close'].resample('BA').mean().plot(color='r', alpha=0.5, style=':')
stock_info['Close'].asfreq('BA').plot(color='g',alpha=0.5,style='--')
plt.legend(['original','resample','asfreq'],loc='upper left')
plt.show()

运行结果:

这里我们着重解释一下红色和绿色两条曲线。

红线是采用resample方法进行重采样所绘制的曲线,我们规定了新的采样频率是年末最后一个工作日(BA),在resample中我们使用的统计量是mean,即求平均值,因此resample每个采样点的数据值就是当年度全部数据值的平均值。

绿线是采用asfreq方法进行重采样所绘制的图,每个采样点就是年末最后一个工作日的数值。

3.关于缺失值的处理

还是举腾讯公司的股价数据来说吧,在节假日,交易所是不交易的,我们选取2019年4月4日~2019年5月4日的所有收盘数据

2019-04-04    376.000000
2019-04-08    380.200012
2019-04-09    383.600006
2019-04-10    388.799988
2019-04-11    391.399994
2019-04-12    393.799988
2019-04-15    388.200012
2019-04-16    393.600006
2019-04-17    395.600006
2019-04-18    391.600006
2019-04-23    393.000000
2019-04-24    393.000000
2019-04-25    382.799988
2019-04-26    384.000000
2019-04-29    390.600006
2019-04-30    388.000000
2019-05-02    391.399994
2019-05-03    387.799988
Name: Close, dtype: float64

我们不难发现,休息日是没有收盘数据的,那么在这种情况下,如果我们按天(注意不是工作日,而是自然日)进行重采样,在休息日的采样点,岂不是采不到数据?那会出现什么情况呢?我们一试便知:

代码片段:
```
from pandas_datareader import data
import matplotlib.pyplot as plt
import pandas as pd
import seaborn
seaborn.set()

stock_code = '0700.hk'
start_date = '2019-04-04'
end_date = '2019-05-04'
stock_info = data.get_data_yahoo(stock_code, start_date, end_date)
print(stock_info['Close'].asfreq('D'))
stock_info['Close'].asfreq('D').plot(marker='o')

top Created with Sketch.