本章主要介绍了时间序列数据处理的3个工具包,帮助读者掌握时间序列在R语言中的数据结构和基本使用。
问题
R语言怎么处理时间序列数据?
引言
时间序列分析是一种动态数据处理的统计方法,通过对时间序列数据的分析,我们可以感觉到世界正改变着什么!R语言作为统计分析的利器,对时间序列处理有着强大的支持。在R语言中,单独为时间序列数据定义了一种数据类型zoo,zoo是时间序列的基础,也是股票分析的基础。本节将介绍zoo库在R语言中的结构和使用。
2.1.1 zoo包介绍
zoo是一个R语言类库,zoo类库中定义了一个名为zoo的S3类型对象,用于描述规则的和不规则的有序的时间序列数据。zoo对象是一个独立的对象,包括索引、日期、时间,只依赖于基础的R环境。zooreg对象继承了zoo对象,只能用于规则的时间序列数据。R语言中很多其他的程序包,都是以zoo和zooreg作为时间序列数据的基础的!zoo包的API主要有6类,下面一一介绍。
(1)基础对象
·zoo:有序的时间序列对象。
·zooreg:规则的时间序列对象,继承zoo对象。与zoo相比,不同之处在于zooreg要求数据是连续的。
(2)类型转换
·as.zoo:把一个对象转型为zoo类型。
·plot.zoo:为plot函数提供zoo的接口。
·xyplot.zoo:为lattice的xyplot函数提供zoo的接口。
·ggplot2.zoo:为ggplot2包提供zoo的接口。
(3)数据操作
·coredata:查看或编辑zoo的数据部分。
·index:查看或编辑zoo的索引部分。
·window.zoo:按时间过滤数据。
·merge.zoo:合并多个zoo对象。
·read.zoo:从文件读写zoo序列。
·aggregate.zoo:计算zoo数据。
·rollapply:对zoo数据的滚动处理。
·rollmean:对zoo数据的滚动计算均值。
(4)NA值处理
·na.fill:NA值的填充。
·na.locf:替换NA值。
·na.aggregate:计算统计值替换NA值。
·na.approx:计算插值替换NA值。
·na.StructTS:计算季节Kalman滤波替换NA值。
·na.trim:过滤有NA的记录。
(5)辅助工具
·is.regular:检查是否是规则的序列。
·lag.zoo:计算步长和差分。
·MATCH:取交集。
·ORDER:值排序,输出索引。
(6)显示控制
·yearqtr:以年季度显示时间。
·yearmon:以年月显示时间。
·xblocks:作图沿x轴分割图形。
·make.par.list:用于给plot.zoo和xyplot.zoo数据格式转换。
2.1.2 zoo安装
本节使用的系统环境是:
·Win764bit
·R:3.0.1x86_64-w64-mingw32/x64b4bit
注 zoo同时支持Windows 7环境和Linux环境。
zoo包的安装过程如下:
~ R # 启动R 程序 > install.packages("zoo") # 安装zoo 包 > library(zoo) # 加载zoo 包
2.1.3 zoo包的使用
1.zoo对象
zoo对象包括两部分,即数据部分和索引部分。首先是函数定义:
zoo(x = NULL, order.by = index(x), frequency = NULL)
其中x是数据部分,允许类型为向量、矩阵、因子;order.by是索引部分,字段唯一性要求,用于排序;frequency是每个时间单元显示的数量。
以下代码构建一个zoo对象,以时间为索引,产生的结果是图2-1。特别要注意的一点是,zoo对象可以接受不连续的时间序列数据。
> x.Date <- as.Date("2003-02-01") + c(1, 3, 7, 9, 14) – 1 # 定义一个不连续的日期的向量 > x.Date [1] "2003-02-01" "2003-02-03" "2003-02-07" "2003-02-09" "2003-02-14" > class(x.Date) [1] "Date" > x <- zoo(rnorm(5), x.Date) # 定义不连续的zoo 对象 > x 2003-02-01 2003-02-03 2003-02-07 2003-02-09 2003-02-14 0.01964254 0.03122887 0.64721059 1.47397924 1.29109889 > class(x) [1] "zoo" > plot(x) # 画图显示
图2-1 时间序列图
接下来,我们以数字为索引创建多组时间序列。用如下代码,生成一个有12个元素的4行3列的矩阵,以数字0:10为索引,创建一个zoo类型对象y,并以图形输出y,产生的结果如图2-2所示。
> y <- zoo(matrix(1:12, 4, 3),0:10) > y 0 1 5 9 1 2 6 10 2 3 7 11 3 4 8 12 4 1 5 9 5 2 6 10 6 3 7 11 7 4 8 12 8 1 5 9 9 2 6 10 10 3 7 11 > plot(y) # 矩阵的每一列为一组时间序列图
图2-2 分组的时间序列图
2.zooreg对象
首先是函数定义:
zooreg(data, start = 1, end = numeric(), frequency = 1, deltat = 1, ts.eps = getOption("ts.eps"), order.by = NULL)
下面是参数说明。
·data:数据部分,允许类型为向量、矩阵、因子。
·start:时间部分,开始时间。
·end:时间部分,结束时间。
·frequency:每个时间单元显示的数量。
·deltat:连续观测的采样周期,不能与frequency同时出现,例如,取每月的数据,为1/12。
·ts.eps:时间序列间隔,当数据时间间隔小于ts.eps时,使用ts.eps作为时间间隔。通过getOption(“ts.eps”)设置,默认是1e-05。
·order.by:索引部分,字段唯一性要求,用于排序,继承zoo的order.by。
以下代码构建一个zooreg对象,以连续的年(季度)时间为索引,产生的结果是图2-3。
> zooreg(1:10, frequency = 4, start = c(1959, 2)) 1959(2) 1959(3) 1959(4) 1960(1) 1960(2) 1960(3) 1960(4) 1961(1) 1961(2) 1961(3) 1 2 3 4 5 6 7 8 9 10 > as.zoo(ts(1:10, frequency = 4, start = c(1959, 2))) 1959(2) 1959(3) 1959(4) 1960(1) 1960(2) 1960(3) 1960(4) 1961(1) 1961(2) 1961(3) 1 2 3 4 5 6 7 8 9 10 > zr<-zooreg(rnorm(10), frequency = 4, start = c(1959, 2)) > plot(zr)
图2-3 zooreg对象的时间序列图
3.zoo对象与zooreg对象的区别
zoo对象与zooreg对象的区别体现在计算步长和差分方面。
·lag(步长):zoo根据索引计算,zooreg根据值计算。
·diff(差分):zoo根据索引计算,zooreg根据值计算。
例如,对同一组值不连续的数据(1,2,3,6,7,8),二者的计算结果如下。
> x <- c(1, 2, 3, 6, 7, 8) > zz <- zoo(x, x) > zr <- as.zooreg(zz) > lag(zz, k = -1) # 计算步长 2 3 6 7 8 1 2 3 6 7 > lag(zr, k = -1) 2 3 4 7 8 9 1 2 3 6 7 8 > diff(zz) # 计算差分 2 3 6 7 8 1 1 3 1 1 > diff(zr) 2 3 7 8 1 1 1 1
4.zoo对象的类型转换
首先,把对象从其他类型转型到zoo类型。
> as.zoo(rnorm(5)) # 把一个基本类型的向量转型到zoo 类型 1 2 3 4 5 -0.4892119 0.5740950 0.7128003 0.6282868 1.0289573 > as.zoo(ts(rnorm(5), start = 1981, freq = 12)) 1981(1) 1981(2) 1981(3) 1981(4) 1981(5) 2.3198504 0.5934895 -1.9375893 -1.9888237 1.0944444 > x <- as.zoo(ts(rnorm(5), start = 1981, freq = 12)); x # 把一个ts 类型转型到zoo 类型 1981(1) 1981(2) 1981(3) 1981(4) 1981(5) 1.8822996 1.6436364 0.1260436 -2.0360960 -0.1387474
其次,把对象从zoo类型转型到其他类型。
> as.matrix(x) # 把zoo 类型,转型到矩阵 x 1981(1) 1.8822996 1981(2) 1.6436364 1981(3) 0.1260436 1981(4) -2.0360960 1981(5) -0.1387474 > as.vector(x) # 把zoo 类型,转型到数字向量 [1] 1.8822996 1.6436364 0.1260436 -2.0360960 -0.1387474 > as.data.frame(x) # 把zoo 类型,转型到数据框 x 1981(1) 1.8822996 1981(2) 1.6436364 1981(3) 0.1260436 1981(4) -2.0360960 1981(5) -0.1387474 > as.list(x) # 把zoo 类型,转型到列表 [[1]] 1981(1) 1981(2) 1981(3) 1981(4) 1981(5) 1.8822996 1.6436364 0.1260436 -2.0360960 -0.1387474
5.用ggplot2画时间序列
由于ggplot2不支持zoo类型的数据,因此需要通过ggplot2::fortify()函数,调用zoo::fortify.zoo()函数,把zoo类型转换成ggplot2可识别的类型后,ggplot2才可以对zoo类型数据的画图。以下代码用ggplot2画zoo类型的时间序列图,产生的结果是图2-4。
> library(scales) > x.Date <- as.Date(paste(2003, 02, c(1, 3, 7, 9, 14), sep = "-")) # 构建数据对象 > x <- zoo(rnorm(5), x.Date) > xlow <- x - runif(5) > xhigh <- x + runif(5) > z <- cbind(x, xlow, xhigh) > z # 显示数据集 x xlow xhigh 2003-02-01 -0.36006612 -0.88751958 0.006247816 2003-02-03 1.35216617 0.97892538 2.076360524 2003-02-07 0.61920828 0.23746410 1.156569424 2003-02-09 0.27516116 0.09978789 0.777878867 2003-02-14 0.02510778 -0.80107410 0.541592929 # 对zoo 类型的数据,用fortify() 转换成data.frame 类型 > g<-ggplot(aes(x = Index, y = Value), data = fortify(x, melt = TRUE)) > g<-g+geom_line() > g<-g+geom_line(aes(x = Index, y = xlow), colour = "red", data = fortify(xlow)) > g<-g+geom_ribbon(aes(x = Index, y = x, ymin = xlow, ymax = xhigh), data =fortify(x), fill = "darkgray") > g<-g+geom_line() > g<-g+xlab("Index") + ylab("x") > g
图2-4 用ggplot2画的时间序列图
6.zoo对象的数据操作
使用coredata()函数修改zoo类型的数据部分。
> x.date <- as.Date(paste(2003, rep(1:4, 4:1), seq(1,20,2), sep = "-")) > x <- zoo(matrix(rnorm(20), ncol = 2), x.date) > coredata(x) # 查看数据部分 [,1] [,2] [1,] -1.04571765 0.92606273 [2,] -0.89621126 0.03693769 [3,] 1.26938716 -1.06620017 [4,] 0.59384095 -0.23845635 [5,] 0.77563432 1.49522344 [6,] 1.55737038 1.17215855 [7,] -0.36540180 -1.45770721 [8,] 0.81655645 0.09505623 [9,] -0.06063478 0.84766496 [10,] -0.50137832 -1.62436453 > coredata(x) <- matrix(1:20, ncol = 2) # 修改数据部分 > x # 查看修改后的数据集 2003-01-01 1 11 2003-01-03 2 12 2003-01-05 3 13 2003-01-07 4 14 2003-02-09 5 15 2003-02-11 6 16 2003-02-13 7 17 2003-03-15 8 18 2003-03-17 9 19 2003-04-19 10 20
使用index()函数修改zoo类型的索引部分。
> x.date <- as.Date(paste(2003, rep(1:4, 4:1), seq(1,20,2), sep = "-")) > x <- zoo(matrix(rnorm(20), ncol = 2), x.date) > index(x) # 查看索引部分 [1] "2003-01-01" "2003-01-03" "2003-01-05" "2003-01-07" "2003-02-09" [6] "2003-02-11" "2003-02-13" "2003-03-15" "2003-03-17" "2003-04-19" > index(x) <- 1:nrow(x) # 修改索引部分 > index(x) # 查看修改后的索引部分 [1] 1 2 3 4 5 6 7 8 9 10
使用window.zoo()函数按时间过滤数据。
> x.date <- as.Date(paste(2003, rep(1:4, 4:1), seq(1,20,2), sep = "-")) > x <- zoo(matrix(rnorm(20), ncol = 2), x.date) > window(x, start = as.Date("2003-02-01"), end = as.Date("2003-03-01")) # 取日期从2003-02-01 到2003-03-01 之间的数据 2003-02-09 0.7021167 -0.3073809 2003-02-11 2.5071111 0.6210542 2003-02-13 -1.8900271 0.1819022 > window(x, index = x.date[1:6], start = as.Date("2003-02-01")) # 取日期从2003-02-01 开始的,且索引日期在x.date[1:6] 中的数据 2003-02-09 0.7021167 -0.3073809 2003-02-11 2.5071111 0.6210542 > window(x, index = x.date[c(4, 8, 10)]) # 取索引日期在x.date[c(4, 8, 10)] 中的数据 2003-01-07 1.4623515 -1.198597 2003-03-15 -0.5898128 1.318401 2003-04-19 -0.4209979 -1.648222
使用merge.zoo()合并多个zoo对象。
> y1 <- zoo(matrix(1:10, ncol = 2), 1:5);y1 # 创建2 个zoo 数据 1 1 6 2 2 7 3 3 8 4 4 9 5 5 10 > y2 <- zoo(matrix(rnorm(10), ncol = 2), 3:7);y2 3 1.4810127 0.13575871 4 -0.3914258 0.06404148 5 0.6018237 1.85017952 6 1.2964150 -0.12927481 7 0.2211769 0.32381709 > merge(y1, y2, all = FALSE) # 以相同的索引值合并数据 y1.1 y1.2 y2.1 y2.2 3 3 8 0.9514985 1.7238941 4 4 9 -1.1131230 -0.2061446 5 5 10 0.6169665 -1.3141951 > merge(y1, y2, all = FALSE, suffixes = c("a", "b")) # 自定义数据列的名字 a.1 a.2 b.1 b.2 3 3 8 0.9514985 1.7238941 4 4 9 -1.1131230 -0.2061446 5 5 10 0.6169665 -1.3141951 > merge(y1, y2, all = TRUE) # 合并完整的数据集,空数据默认以NA 填充 y1.1 y1.2 y2.1 y2.2 1 1 6 NA NA 2 2 7 NA NA 3 3 8 0.9514985 1.7238941 4 4 9 -1.1131230 -0.2061446 5 5 10 0.6169665 -1.3141951 6 NA NA 0.5134937 0.0634741 7 NA NA 0.3694591 -0.2319775 > merge(y1, y2, all = TRUE, fill = 0) # 合并完整的数据集,空数据以0 填充 y1.1 y1.2 y2.1 y2.2 1 1 6 0.0000000 0.0000000 2 2 7 0.0000000 0.0000000 3 3 8 0.9514985 1.7238941 4 4 9 -1.1131230 -0.2061446 5 5 10 0.6169665 -1.3141951 6 0 0 0.5134937 0.0634741 7 0 0 0.3694591 -0.2319775
使用aggregate.zoo()函数对zoo数据进行计算。
> x.date <- as.Date(paste(2004, rep(1:4, 4:1), seq(1,20,2), sep = "-")) # 创建zoo 类型数据集x > x <- zoo(rnorm(12), x.date); x 2004-01-01 2004-01-03 2004-01-05 2004-01-07 2004-02-09 2004-02-11 0.67392868 1.95642526 -0.26904101 -1.24455152 -0.39570292 0.09739665 2004-02-13 2004-03-15 2004-03-17 2004-04-19 -0.23838695 -0.41182796 -1.57721805 -0.79727610 > x.date2 <- as.Date(paste(2004, rep(1:4, 4:1), 1, sep = "-")); x.date2 # 创建时间向量x.date2 [1] "2004-01-01" "2004-01-01" "2004-01-01" "2004-01-01" "2004-02-01" [6] "2004-02-01" "2004-02-01" "2004-03-01" "2004-03-01" "2004-04-01" > x2 <- aggregate(x, x.date2, mean); x2 # 计算x 以x.date2 为时间分割规则的均值 2004-01-01 2004-02-01 2004-03-01 2004-04-01 0.2791904 -0.1788977 -0.9945230 -0.7972761
7.zoo对象数据函数化处理
使用rollapply()函数对zoo数据进行函数化处理。
> z <- zoo(11:15, as.Date(31:35)) > rollapply(z, 2, mean) # 从起始日开始,计算连续2 日的均值 1970-02-01 1970-02-02 1970-02-03 1970-02-04 11.5 12.5 13.5 14.5 > rollapply(z, 3, mean) # 从起始日开始,计算连续3 日的均值 1970-02-02 1970-02-03 1970-02-04 12 13 14
等价操作变换:用rollapply()实现aggregate()的操作。
> z2 <- zoo(rnorm(6)) > rollapply(z2, 3, mean, by = 3) # means of nonoverlapping groups of 3 2 5 -0.3065197 0.6350963 > aggregate(z2, c(3,3,3,6,6,6), mean) # same 3 6 -0.3065197 0.6350963
等价操作变换:用rollapply()实现rollmean()的操作。
> rollapply(z2, 3, mean) # uses rollmean which is optimized for mean 2 3 4 5 -0.3065197 -0.7035811 -0.1672344 0.6350963 > rollmean(z2, 3) # same 2 3 4 5 -0.3065197 -0.7035811 -0.1672344 0.6350963
8.NA值处理
使用na.fill()函数进行NA填充。
> z <- zoo(c(NA, 2, NA, 3, 4, 5, 9, NA));z # 创建有NA 值的zoo 对象 1 2 3 4 5 6 7 8 NA 2 NA 3 4 5 9 NA > na.fill(z, "extend") # 用extend 的方法,填充NA 值,即NA 前后项的均值填充 1 2 3 4 5 6 7 8 2.0 2.0 2.5 3.0 4.0 5.0 9.0 9.0 > na.fill(z, -(1:3)) # 自定义填充NA 值,即-(1:3) 循环填充 1 2 3 4 5 6 7 8 -1 2 -2 3 4 5 9 -3 > na.fill(z, c("extend", NA)) # 用extend ,配合自定义的方法,即extend 和自定义规则循环填充 1 2 3 4 5 6 7 8 2 2 NA 3 4 5 9 9
使用na.locf()函数进行NA替换。
> z <- zoo(c(NA, 2, NA, 3, 4, 5, 9, NA, 11));z 1 2 3 4 5 6 7 8 9 NA 2 NA 3 4 5 9 NA 11 > na.locf(z) # 用NA 的前一项的值,替换NA 值 2 3 4 5 6 7 8 9 2 2 3 4 5 9 9 11 > na.locf(z, fromLast = TRUE) # 用NA 的后一项的值,替换NA 值 1 2 3 4 5 6 7 8 9 2 2 3 3 4 5 9 11 11
使用na.aggregate()函数的统计计算的值替换NA值。
> z <- zoo(c(1, NA, 3:9),c(as.Date("2010-01-01") + 0:2,as.Date("2010-02-01") + 0:2,as.Date("2011-01-01") + 0:2));z 2010-01-01 2010-01-02 2010-01-03 2010-02-01 2010-02-02 2010-02-03 2011-01-01 1 NA 3 4 5 6 7 2011-01-02 2011-01-03 8 9 > na.aggregate(z) # 计算排除NA 的其他项的均值,替换NA 值 2010-01-01 2010-01-02 2010-01-03 2010-02-01 2010-02-02 2010-02-03 2011-01-01 1.000 5.375 3.000 4.000 5.000 6.000 7.000 2011-01-02 2011-01-03 8.000 9.000 > na.aggregate(z, as.yearmon) # 以索引的年月分组的均值,替换NA 值 2010-01-01 2010-01-02 2010-01-03 2010-02-01 2010-02-02 2010-02-03 2011-01-01 1 2 3 4 5 6 7 2011-01-02 2011-01-03 8 9 > na.aggregate(z, months) # 以索引的月份分组的均值,替换NA 值 2010-01-01 2010-01-02 2010-01-03 2010-02-01 2010-02-02 2010-02-03 2011-01-01 1.0 5.6 3.0 4.0 5.0 6.0 7.0 2011-01-02 2011-01-03 8.0 9.0 > na.aggregate(z, format, "%Y") # 以正则表示的索引的年份分组的均值,替换NA 值 2010-01-01 2010-01-02 2010-01-03 2010-02-01 2010-02-02 2010-02-03 2011-01-01 1.0 3.8 3.0 4.0 5.0 6.0 7.0 2011-01-02 2011-01-03 8.0 9.0
使用na.approx()函数计算插值替换NA值。
> z <- zoo(c(2, NA, 1, 4, 5, 2), c(1, 3, 4, 6, 7, 8));z 1 3 4 6 7 8 2 NA 1 4 5 2 > na.approx(z) 1 3 4 6 7 8 2.000000 1.333333 1.000000 4.000000 5.000000 2.000000 > na.approx(z, 1:6) 1 3 4 6 7 8 2.0 1.5 1.0 4.0 5.0 2.0
使用na.StructTS()函数计算季节Kalman滤波替换NA值,产生的结果是图2-5。
> z <- zooreg(rep(10 * seq(4), each = 4) + rep(c(3, 1, 2, 4), times = 4), start = as.yearqtr(2000), freq = 4) > z[10] <- NA > zout <- na.StructTS(z);zout > plot(cbind(z, zout), screen = 1, col = 1:2, type = c("l", "p"), pch = 20)
图2-5 替换NA值的时间序列
使用na.trim()函数,去掉有NA的行。
> xx <- zoo(matrix(c(1, 4, 6, NA, NA, 7), 3), c(2, 4, 6));xx 2 1 NA 4 4 NA 6 6 7 > na.trim(xx) 6 6 7
9.数据显示格式
以“年+季度”格式输出
> x <- as.yearqtr(2000 + seq(0, 7)/4);x # 以年季默认格式输出 [1] "2000 Q1" "2000 Q2" "2000 Q3" "2000 Q4" "2001 Q1" "2001 Q2" "2001 Q3" [8] "2001 Q4" > format(x, "%Y Quarter %q") # 以年季自定义格式输出 [1] "2000 Quarter 1" "2000 Quarter 2" "2000 Quarter 3" "2000 Quarter 4" [5] "2001 Quarter 1" "2001 Quarter 2" "2001 Quarter 3" "2001 Quarter 4" > as.yearqtr("2001 Q2") [1] "2001 Q2" > as.yearqtr("2001 q2") [1] "2001 Q2" > as.yearqtr("2001-2") [1] "2001 Q2"
以“年+月份”格式输出
> x <- as.yearmon(2000 + seq(0, 23)/12) ;x # 以年月默认格式输出 [1] " 一月 2000" " 二月 2000" " 三月 2000" " 四月 2000" " 五月 2000" [6] " 六月 2000" " 七月 2000" " 八月 2000" " 九月 2000" " 十月 2000" [11] " 十一月 2000" " 十二月 2000" " 一月 2001" " 二月 2001" " 三月 2001" [16] " 四月 2001" " 五月 2001" " 六月 2001" " 七月 2001" " 八月 2001" [21] " 九月 2001" " 十月 2001" " 十一月 2001" " 十二月 2001" > as.yearmon("mar07", "%b%y") [1] NA > as.yearmon("2007-03-01") [1] " 三月 2007" > as.yearmon("2007-12") [1] " 十二月 2007"
10.区间分割
使用xblock()函数,以不同的颜色划分3个区间,即(-Inf,15)、[15,30]和(30,Inf),产生的是图2-6。
图2-6 有分割线的时间序列
> set.seed(0) > flow <- ts(filter(rlnorm(200, mean = 1), 0.8, method = "r")) > rgb <- hcl(c(0, 0, 260), c = c(100, 0, 100), l = c(50, 90, 50), alpha = 0.3) > plot(flow) > xblocks(flow > 30, col = rgb[1]) ## high values red > xblocks(flow < 15, col = rgb[3]) ## low value blue > xblocks(flow >= 15 & flow <= 30, col = rgb[2]) ## the rest gray
11.从文件读入时间序列数据创建zoo对象
我们首先创建一个文件,并将其命名为read.csv,代码如下。
~ vi read.csv 2003-01-01,1.0073644,0.05579711 2003-01-03,-0.2731580,0.06797239 2003-01-05,-1.3096795,-0.20196174 2003-01-07,0.2225738,-1.15801525 2003-02-09,1.1134332,-0.59274327 2003-02-11,0.8373944,0.76606538 2003-02-13,0.3145168,0.03892812 2003-03-15,0.2222181,0.01464681 2003-03-17,-0.8436154,-0.18631697 2003-04-19,0.4438053,1.40059083
然后读入文件并生成zoo序列。
> r <- read.zoo(file="read.csv",sep = ",", format = "%Y-%m-%d") # 以zoo 格式读入数据 > r # 查看数据 V2 V3 2003-01-01 1.0073644 0.05579711 2003-01-03 -0.2731580 0.06797239 2003-01-05 -1.3096795 -0.20196174 2003-01-07 0.2225738 -1.15801525 2003-02-09 1.1134332 -0.59274327 2003-02-11 0.8373944 0.76606538 2003-02-13 0.3145168 0.03892812 2003-03-15 0.2222181 0.01464681 2003-03-17 -0.8436154 -0.18631697 2003-04-19 0.4438053 1.40059083 > class(r) # 查看数据类型 [1] "zoo"
我们已经完全掌握了zoo库及zoo对象的使用,接下来就可以放手去用R处理时间序列数据了!
问题
如何进行复杂的时间序列数据处理?
引言
本节将继续2.1节,介绍zoo包的扩展实现。看上去简单的时间序列,却内含复杂的规律。zoo作为时间序列的基础库,是面向通用的设计,可以用来定义股票数据,也可以分析天气数据。但由于业务行为的不同,我们需要更多的辅助函数帮助我们更高效地完成任务。xts扩展了zoo,提供更多的数据处理和数据变换的函数。
2.2.1 xts介绍
xts是对时间序列数据(zoo)的一种扩展实现,目标是为了统一时间序列的操作接口。实际上,xts类型继承了zoo类型,丰富了时间序列数据处理的函数,API定义更贴近使用者,更实用,更简单!
1.xts数据结构
xts扩展zoo的基础结构,由3部分组成,如图2-7所示。
·索引部分:时间类型向量。
·数据部分:以矩阵为基础类型,支持可以与矩阵相互转换的任何类型。
·属性部分:附件信息,包括时区和索引时间类型的格式等。
图2-7 xts数据结构
2.xts的API介绍
(1)xts基础
·xts:定义xts数据类型,继承zoo类型。
·coredata.xts:查看或编辑xts对象的数据部分。
·xtsAttributes:查看或编辑xts对象的属性部分。
·[.xts]:用[]语法,取数据子集。
·dimnames.xts:查看或编辑xts维度名。
·sample_matrix:测试数据集,包括180条xts对象的记录,matrix类型。
·xtsAPI:C语言API接口。
(2)类型转换
·as.xts:转换对象到xts(zoo)类型。
·as.xts.methods:转换对象到xts函数。
·plot.xts:为plot函数提供xts的接口作图。
·.parseISO8601:把字符串(ISO8601格式)输出为POSIXct类型的,包括开始时间和结束时间的list对象。
·firstof:创建一个开始时间,POSIXct类型。
·lastof:创建一个结束时间,POSIXct类型。
·indexClass:取索引类型。
·.indexDate:索引的日期。
·.indexday:索引的日期,同.indexDate。
·.indexyday:索引的年(日)值。
·.indexmday:索引的月(日)值。
·.indexwday:索引的周(日)值。
·.indexweek:索引的周值。
·.indexmon:索引的月值。
·.indexyear:索引的年值。
·.indexhour:索引的时值。
·.indexmin:索引的分值。
·.indexsec:索引的秒值。
(3)数据处理
·align.time:以下一个时间对齐数据,秒,分钟,小时。
·endpoints:按时间单元提取索引数据。
·merge.xts:合并多个xts对象,重写zoo::merge.zoo函数。
·rbind.xts:数据按行合并,为rbind函数提供xts的接口。
·split.xts:数据分割,为split函数,提供xts的接口。
·na.locf.xts:替换NA值,重写zoo:na.locf函数。
(4)数据统计
·apply.daily:按日分割数据,执行函数。
·apply.weekly:按周分割数据,执行函数。
·apply.monthly:按月分割数据,执行函数。
·apply.quarterly:按季分割数据,执行函数。
·apply.yearly:按年分割数据,执行函数。
·to.period:按期间分割数据。
·period.apply:按期间执行自定义函数。
·period.max:按期间计算最大值。
·period.min:按期间计算最小值。
·period.prod:按期间计算指数。
·period.sum:按期间求和。
·nseconds:计算数据集包括多少秒。
·nminutes:计算数据集包括多少分。
·nhours:计算数据集包括多少时。
·ndays:计算数据集包括多少日。
·nweeks:计算数据集包括多少周。
·nmonths:计算数据集包括多少月。
·nquarters:计算数据集包括多少季。
·nyears:计算数据集包括多少年。
·periodicity:查看时间序列的期间。
(5)辅助工具
·first:从开始到结束设置条件取子集。
·last:从结束到开始设置条件取子集。
·timeBased:判断是否是时间类型。
·timeBasedSeq:创建时间的序列。
·diff.xts:计算步长和差分。
·isOrdered:检查向量是否是顺序的。
·make.index.unique:强制时间唯一,增加毫秒随机数。
·axTicksByTime:计算X轴刻度标记位置按时间描述。
·indexTZ:查询xts对象的时区。
2.2.2 xts包的安装
本节使用的系统环境是:
·Win764bit
·R:3.0.1x86_64-w64-mingw32/x64b4bit
注 xts同时支持Windows 7环境和Linux环境。
xts的安装过程如下:
~ R # 启动R 程序 > install.packages("xts") # 安装xts 包 also installing the dependency 'zoo' > library(xts) # 加载xts
2.2.3 xts包的使用
1.xts对象的基本操作
查看xts包中的测试数据集sample_matrix。
> data(sample_matrix) # 加载sample_matrix 数据集 > head(sample_matrix) # 查看sample_matrix 数据集的前6 条数据 Open High Low Close 2007-01-02 50.03978 50.11778 49.95041 50.11778 2007-01-03 50.23050 50.42188 50.23050 50.39767 2007-01-04 50.42096 50.42096 50.26414 50.33236 2007-01-05 50.37347 50.37347 50.22103 50.33459 2007-01-06 50.24433 50.24433 50.11121 50.18112 2007-01-07 50.13211 50.21561 49.99185 49.99185
接下来,定义一个xts类型对象。
> sample.xts <- as.xts(sample_matrix, descr='my new xts object') # 创建一个xts 对象,并设置属性descr > class(sample.xts) # xts 是继承zoo 类型的对象 [1] "xts" "zoo" > str(sample.xts) # 打印对象结构 An 'xts' object on 2007-01-02/2007-06-30 containing: Data: num [1:180, 1:4] 50 50.2 50.4 50.4 50.2 ... - attr(*, "dimnames")=List of 2 ..$ : NULL ..$ : chr [1:4] "Open" "High" "Low" "Close" Indexed by objects of class: [POSIXct,POSIXt] TZ: xts Attributes: List of 1 $ descr: chr "my new xts object" > attr(sample.xts,'descr') # 查看对象的属性descr [1] "my new xts object"
在[]中,通过字符串匹配进行xts数据查询。
> head(sample.xts['2007']) # 选出2007 年的数据 Open High Low Close 2007-01-02 50.03978 50.11778 49.95041 50.11778 2007-01-03 50.23050 50.42188 50.23050 50.39767 2007-01-04 50.42096 50.42096 50.26414 50.33236 2007-01-05 50.37347 50.37347 50.22103 50.33459 2007-01-06 50.24433 50.24433 50.11121 50.18112 2007-01-07 50.13211 50.21561 49.99185 49.99185 > head(sample.xts['2007-03/']) # 选出2007 年03 月的数据 Open High Low Close 2007-03-01 50.81620 50.81620 50.56451 50.57075 2007-03-02 50.60980 50.72061 50.50808 50.61559 2007-03-03 50.73241 50.73241 50.40929 50.41033 2007-03-04 50.39273 50.40881 50.24922 50.32636 2007-03-05 50.26501 50.34050 50.26501 50.29567 2007-03-06 50.27464 50.32019 50.16380 50.16380 > head(sample.xts['2007-03-06/2007']) # 选出2007 年03 月06 日到2007 年的数据 Open High Low Close 2007-03-06 50.27464 50.32019 50.16380 50.16380 2007-03-07 50.14458 50.20278 49.91381 49.91381 2007-03-08 49.93149 50.00364 49.84893 49.91839 2007-03-09 49.92377 49.92377 49.74242 49.80712 2007-03-10 49.79370 49.88984 49.70385 49.88698 2007-03-11 49.83062 49.88295 49.76031 49.78806 > sample.xts['2007-01-03'] # 选出2007 年01 月03 日的数据 Open High Low Close 2007-01-03 50.2305 50.42188 50.2305 50.39767
2.用xts对象画图
用xts对象可以画曲线图(图2-8)和K线图(图2-9),下面是产生这两种图的代码,首先是曲线图:
> data(sample_matrix) > plot(as.xts(sample_matrix)) Warning message: In plot.xts(as.xts(sample_matrix)) : only the univariate series will be plotted
警告信息提示,只有单变量序列将被绘制,即只画出第一列数据sample_matrix[,1]的曲线。
图2-8 曲线图
然后是K线图:
> plot(as.xts(sample_matrix), type='candles') # 画K 线图
图2-9 K线图
3.xts对象的类型转换
创建首尾时间函数firstof()和lastof()。
> firstof(2000) # 2000 年的第一天,时分秒显示省略 [1] "2000-01-01 CST" > firstof(2005,01,01) [1] "2005-01-01 CST" > lastof(2007) # 2007 年的最后一天,最后一秒 [1] "2007-12-31 23:59:59.99998 CST" > lastof(2007,10) [1] "2007-10-31 23:59:59.99998 CST"
创建首尾时间。
> .parseISO8601('2000') # 以ISO8601 格式,创建2000 年首尾时间 $first.time [1] "2000-01-01 CST" $last.time [1] "2000-12-31 23:59:59.99998 CST" > .parseISO8601('2000-05/2001-02') # 以ISO8601 格式,创建2000 年05 月开始,2001 年02 月结束的时间 $first.time [1] "2000-05-01 CST" $last.time [1] "2001-02-28 23:59:59.99998 CST" > .parseISO8601('2000-01/02') $first.time [1] "2000-01-01 CST" $last.time [1] "2000-02-29 23:59:59.99998 CST" > .parseISO8601('T08:30/T15:00') $first.time [1] "1970-01-01 08:30:00 CST" $last.time [1] "1970-12-31 15:00:59.99999 CST"
创建以时间类型为索引的xts对象。
> x <- timeBasedSeq('2010-01-01/2010-01-02 12:00') # 创建POSIXt 类型时间 > head(x) [1] "2010-01-01 00:00:00 CST" [2] "2010-01-01 00:01:00 CST" [3] "2010-01-01 00:02:00 CST" [4] "2010-01-01 00:03:00 CST" [5] "2010-01-01 00:04:00 CST" [6] "2010-01-01 00:05:00 CST" > class(x) [1] "POSIXt" "POSIXct" > x <- xts(1:length(x), x) # 以时间为索引创建xts 对象 > head(x) [,1] 2010-01-01 00:00:00 1 2010-01-01 00:01:00 2 2010-01-01 00:02:00 3 2010-01-01 00:03:00 4 2010-01-01 00:04:00 5 2010-01-01 00:05:00 6 > indexClass(x) [1] "POSIXt" "POSIXct"
格式化索引时间的显示。
> indexFormat(x) <- "%Y-%b-%d %H:%M:%OS3" # 通过正则格式化索引的时间显示 > head(x) [,1] 2010- 一月-01 00:00:00.000 1 2010- 一月-01 00:01:00.000 2 2010- 一月-01 00:02:00.000 3 2010- 一月-01 00:03:00.000 4 2010- 一月-01 00:04:00.000 5 2010- 一月-01 00:05:00.000 6
查看索引时间。
> .indexhour(head(x)) # 按小时取索引时间 [1] 0 0 0 0 0 0 > .indexmin(head(x)) # 按分钟取索引时间 [1] 0 1 2 3 4 5
4.xts对象的数据处理
数据对齐。
> x <- Sys.time() + 1:30 > align.time(x, 10) # 整10 秒对齐,秒位为10 的整数倍 [1] "2013-11-18 15:42:30 CST" "2013-11-18 15:42:30 CST" [3] "2013-11-18 15:42:30 CST" "2013-11-18 15:42:40 CST" [5] "2013-11-18 15:42:40 CST" "2013-11-18 15:42:40 CST" [7] "2013-11-18 15:42:40 CST" "2013-11-18 15:42:40 CST" [29] "2013-11-18 15:43:00 CST" "2013-11-18 15:43:00 CST" > align.time(x, 60) # 整60 秒对齐,秒位为0 ,分位为整数 [1] "2013-11-18 15:43:00 CST" "2013-11-18 15:43:00 CST" [3] "2013-11-18 15:43:00 CST" "2013-11-18 15:43:00 CST" [5] "2013-11-18 15:43:00 CST" "2013-11-18 15:43:00 CST" [7] "2013-11-18 15:43:00 CST" "2013-11-18 15:43:00 CST" [9] "2013-11-18 15:43:00 CST" "2013-11-18 15:43:00 CST" [11] "2013-11-18 15:43:00 CST" "2013-11-18 15:43:00 CST"
按时间分割数据,并计算。
> xts.ts <- xts(rnorm(231),as.Date(13514:13744,origin="1970-01-01")) > apply.monthly(xts.ts,mean) # 按月计算均值,以每月的最后一日显示 [,1] 2007-01-31 0.17699984 2007-02-28 0.30734220 2007-03-31 -0.08757189 2007-04-30 0.18734688 2007-05-31 0.04496954 2007-06-30 0.06884836 2007-07-31 0.25081814 2007-08-19 -0.28845938 > apply.monthly(xts.ts,function(x) var(x)) # 按月计算自定义函数( 方差) ,以每月的最后一日显示 [,1] 2007-01-31 0.9533217 2007-02-28 0.9158947 2007-03-31 1.2821450 2007-04-30 1.2805976 2007-05-31 0.9725438 2007-06-30 1.5228904 2007-07-31 0.8737030 2007-08-19 0.8490521 > apply.quarterly(xts.ts,mean) # 按季计算均值,以每季的最后一日显示 [,1] 2007-03-31 0.12642053 2007-06-30 0.09977926 2007-08-19 0.04589268 > apply.yearly(xts.ts,mean) # 按年计算均值,以年季的最后一日显示 [,1] 2007-08-19 0.09849522
使用to.period()函数按间隔分割数据。
> data(sample_matrix) > to.period(sample_matrix) # 默认按月分割矩阵数据 sample_matrix.Open sample_matrix.High sample_matrix.Low sample_matrix.Close 2007-01-31 50.03978 50.77336 49.76308 50.22578 2007-02-28 50.22448 51.32342 50.19101 50.77091 2007-03-31 50.81620 50.81620 48.23648 48.97490 2007-04-30 48.94407 50.33781 48.80962 49.33974 2007-05-31 49.34572 49.69097 47.51796 47.73780 2007-06-30 47.74432 47.94127 47.09144 47.76719 > class(to.period(sample_matrix)) [1] "matrix" > samplexts <- as.xts(sample_matrix) # 默认按月分割xts 类型数据 > to.period(samplexts) samplexts.Open samplexts.High samplexts.Low samplexts.Close 2007-01-31 50.03978 50.77336 49.76308 50.22578 2007-02-28 50.22448 51.32342 50.19101 50.77091 2007-03-31 50.81620 50.81620 48.23648 48.97490 2007-04-30 48.94407 50.33781 48.80962 49.33974 2007-05-31 49.34572 49.69097 47.51796 47.73780 2007-06-30 47.74432 47.94127 47.09144 47.76719 > class(to.period(samplexts)) [1] "xts" "zoo"
使用endpoints()函数,按间隔分割索引数据。
> data(sample_matrix) > endpoints(sample_matrix) # 默认按月分割 [1] 0 30 58 89 119 150 180 > endpoints(sample_matrix, 'days',k=7) # 按每7 日分割 [1] 0 6 13 20 27 34 41 48 55 62 69 76 83 90 97 104 111 118 125 [20] 132 139 146 153 160 167 174 180 > endpoints(sample_matrix, 'weeks') # 按周分割 [1] 0 7 14 21 28 35 42 49 56 63 70 77 84 9 1 98 105 112 119 126 [20] 133 140 147 154 161 168 175 180 > endpoints(sample_matrix, 'months') # 按月分割 [1] 0 30 58 89 119 150 180
使用merge()函数进行数据合并,按列合并。
> (x <- xts(4:10, Sys.Date()+4:10)) # 创建2 个xts 数据集 [,1] 2013-11-22 4 2013-11-23 5 2013-11-24 6 2013-11-25 7 2013-11-26 8 2013-11-27 9 2013-11-28 10 > (y <- xts(1:6, Sys.Date()+1:6)) [,1] 2013-11-19 1 2013-11-20 2 2013-11-21 3 2013-11-22 4 2013-11-23 5 2013-11-24 6 > merge(x,y) # 按列合并数据,空项以NA 填空 x y 2013-11-19 NA 1 2013-11-20 NA 2 2013-11-21 NA 3 2013-11-22 4 4 2013-11-23 5 5 2013-11-24 6 6 2013-11-25 7 NA 2013-11-26 8 NA 2013-11-27 9 NA 2013-11-28 10 NA > merge(x,y, join='inner') # 按索引合并数据 x y 2013-11-22 4 4 2013-11-23 5 5 2013-11-24 6 6 > merge(x,y, join='left') # 以左侧为基础合并数据 x y 2013-11-22 4 4 2013-11-23 5 5 2013-11-24 6 6 2013-11-25 7 NA 2013-11-26 8 NA 2013-11-27 9 NA 2013-11-28 10 NA
使用rbind()函数进行数据合并,按行合并。
> x <- xts(1:3, Sys.Date()+1:3) > rbind(x,x) # 按行合并数据 [,1] 2013-11-19 1 2013-11-19 1 2013-11-20 2 2013-11-20 2 2013-11-21 3 2013-11-21 3
使用split()函数进行数据切片,按行切片。
> data(sample_matrix) > x <- as.xts(sample_matrix) > split(x)[[1]] # 默认按月进行切片,打印第一个月的数据 Open High Low Close 2007-01-02 50.03978 50.11778 49.95041 50.11778 2007-01-03 50.23050 50.42188 50.23050 50.39767 2007-01-04 50.42096 50.42096 50.26414 50.33236 2007-01-05 50.37347 50.37347 50.22103 50.33459 2007-01-06 50.24433 50.24433 50.11121 50.18112 2007-01-07 50.13211 50.21561 49.99185 49.99185 2007-01-08 50.03555 50.10363 49.96971 49.98806 > split(x, f="weeks")[[1]] # 按周切片,打印前1 周数据 Open High Low Close 2007-01-02 50.03978 50.11778 49.95041 50.11778 2007-01-03 50.23050 50.42188 50.23050 50.39767 2007-01-04 50.42096 50.42096 50.26414 50.33236 2007-01-05 50.37347 50.37347 50.22103 50.33459 2007-01-06 50.24433 50.24433 50.11121 50.18112 2007-01-07 50.13211 50.21561 49.99185 49.99185 2007-01-08 50.03555 50.10363 49.96971 49.98806
NA值处理。
> x <- xts(1:10, Sys.Date()+1:10) > x[c(1,2,5,9,10)] <- NA > x [,1] 2013-11-19 NA 2013-11-20 NA 2013-11-21 3 2013-11-22 4 2013-11-23 NA 2013-11-24 6 2013-11-25 7 2013-11-26 8 2013-11-27 NA 2013-11-28 NA > na.locf(x) # 取NA 的前一个,替换NA 值 [,1] 2013-11-19 NA 2013-11-20 NA 2013-11-21 3 2013-11-22 4 2013-11-23 4 2013-11-24 6 2013-11-25 7 2013-11-26 8 2013-11-27 8 2013-11-28 8 > na.locf(x, fromLast=TRUE) # 取NA 后一个,替换NA 值 [,1] 2013-11-19 3 2013-11-20 3 2013-11-21 3 2013-11-22 4 2013-11-23 6 2013-11-24 6 2013-11-25 7 2013-11-26 8 2013-11-27 NA 2013-11-28 NA
5.xts对象的数据统计计算
对xts对象可以进行各种数据统计计算,比如取开始时间和结束时间,计算时间区间,按期间计算统计指标。
(1)取xts对象的开始时间和结束时间,具体代码如下:
> xts.ts <- xts(rnorm(231),as.Date(13514:13744,origin="1970-01-01")) > start(xts.ts) # 取开始时间 [1] "2007-01-01" > end(xts.ts) # 取结束时间 [1] "2007-08-19" > periodicity(xts.ts) # 以日为单位,打印开始和结束时间 Daily periodicity from 2007-01-01 to 2007-08-19
(2)计算时间区间函数,具体代码如下:
> data(sample_matrix) > ndays(sample_matrix) # 计算数据有多少日 [1] 180 > nweeks(sample_matrix) # 计算数据有多少周 [1] 26 > nmonths(sample_matrix) # 计算数据有多少月 [1] 6 > nquarters(sample_matrix) # 计算数据有多少季 [1] 2 > nyears(sample_matrix) # 计算数据有多少年 [1] 1
(3)按期间计算统计指标,具体代码如下:
> zoo.data <- zoo(rnorm(31)+10,as.Date(13514:13744,origin="1970-01-01")) > ep <- endpoints(zoo.data,'weeks') # 按周获得期间索引 > ep [1] 0 7 14 21 28 35 42 49 56 63 70 77 84 91 98 105 112 119 [19] 126 133 140 147 154 161 168 175 182 189 196 203 210 217 224 231 > period.apply(zoo.data, INDEX=ep, FUN=function(x) mean(x)) # 计算周的均值 2007-01-07 2007-01-14 2007-01-21 2007-01-28 2007-02-04 2007-02-11 2007-02-18 10.200488 9.649387 10.304151 9.864847 10.382943 9.660175 9.857894 2007-02-25 2007-03-04 2007-03-11 2007-03-18 2007-03-25 2007-04-01 2007-04-08 10.495037 9.569531 10.292899 9.651616 10.089103 9.961048 10.304860 2007-04-15 2007-04-22 2007-04-29 2007-05-06 2007-05-13 2007-05-20 2007-05-27 9.658432 9.887531 10.608082 9.747787 10.052955 9.625730 10.430030 2007-06-03 2007-06-10 2007-06-17 2007-06-24 2007-07-01 2007-07-08 2007-07-15 9.814703 10.224869 9.509881 10.187905 10.229310 10.261725 9.855776 2007-07-22 2007-07-29 2007-08-05 2007-08-12 2007-08-19 9.445072 10.482020 9.844531 10.200488 9.649387 > head(period.max(zoo.data, INDEX=ep)) # 计算周的最大值 [,1] 2007-01-07 12.05912 2007-01-14 10.79286 2007-01-21 11.60658 2007-01-28 11.63455 2007-02-04 12.05912 2007-02-11 10.67887 > head(period.min(zoo.data, INDEX=ep)) # 计算周的最小值 [,1] 2007-01-07 8.874509 2007-01-14 8.534655 2007-01-21 9.069773 2007-01-28 8.461555 2007-02-04 9.421085 2007-02-11 8.534655 > head(period.prod(zoo.data, INDEX=ep)) # 计算周的一个指数值 [,1] 2007-01-07 11140398 2007-01-14 7582350 2007-01-21 11930334 2007-01-28 8658933 2007-02-04 12702505 2007-02-11 7702767
6.xts对象的时间序列操作
检查时间类型。
> class(Sys.time());timeBased(Sys.time()) # Sys.time() 是时间类型POSIXct [1] "POSIXct" "POSIXt" [1] TRUE > class(Sys.Date());timeBased(Sys.Date()) # Sys.Date() 是时间类型Date [1] "Date" [1] TRUE > class(20070101);timeBased(20070101) # 20070101 不是时间类型 [1] "numeric" [1] FALSE
使用timeBasedSeq()函数创建时间序列。
> timeBasedSeq('1999/2008') # 按年 [1] "1999-01-01" "2000-01-01" "2001-01-01" "2002-01-01" "2003-01-01" [6] "2004-01-01" "2005-01-01" "2006-01-01" "2007-01-01" "2008-01-01" > head(timeBasedSeq('199901/2008')) # 按月 [1] " 十二月 1998" " 一月 1999" " 二月 1999" " 三月 1999" " 四月 1999" [6] " 五月 1999" > head(timeBasedSeq('199901/2008/d'),40) # 按日 [1] " 十二月1998" " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" [6] " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" [11] " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" [16] " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" [21] " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" [26] " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" " 一月 1999" [31] " 一月 1999" " 一月 1999" " 二月 1999" " 二月 1999" " 二月 1999" [36] " 二月 1999" " 二月 1999" " 二月 1999" " 二月 1999" " 二月 1999" > timeBasedSeq('20080101 0830',length=100) # 按数量创建,100 分钟的数据集 $from [1] "2008-01-01 08:30:00 CST" $to [1] NA $by [1] "mins" $length.out [1] 100
按索引取数据first()和last()。
> x <- xts(1:100, Sys.Date()+1:100) > head(x) [,1] 2013-11-19 1 2013-11-20 2 2013-11-21 3 2013-11-22 4 2013-11-23 5 2013-11-24 6 > first(x, 10) # 取前10 条数据 [,1] 2013-11-19 1 2013-11-20 2 2013-11-21 3 2013-11-22 4 2013-11-23 5 2013-11-24 6 2013-11-25 7 2013-11-26 8 2013-11-27 9 2013-11-28 10 > first(x, '1 day') # 取1 天的数据 [,1] 2013-11-19 1 > last(x, '1 weeks') # 取最后1 周的数据 [,1] 2014-02-24 98 2014-02-25 99 2014-02-26 100
计算步长lag()和差分diff()。
> x <- xts(1:5, Sys.Date()+1:5) > lag(x) # 以1 为步长 [,1] 2013-11-19 NA 2013-11-20 1 2013-11-21 2 2013-11-22 3 2013-11-23 4 > lag(x, k=-1, na.pad=FALSE) # 以-1 为步长,并去掉NA 值 [,1] 2013-11-19 2 2013-11-20 3 2013-11-21 4 2013-11-22 5 > diff(x) # 1 阶差分 [,1] 2013-11-19 NA 2013-11-20 1 2013-11-21 1 2013-11-22 1 2013-11-23 1 > diff(x,lag=2) # 2 阶差分 [,1] 2013-11-19 NA 2013-11-20 NA 2013-11-21 2 2013-11-22 2 2013-11-23 2
使用isOrdered()函数,检查向量是否排序好的。
> isOrdered(1:10, increasing=TRUE) [1] TRUE > isOrdered(1:10, increasing=FALSE) [1] FALSE > isOrdered(c(1,1:10), increasing=TRUE) [1] FALSE > isOrdered(c(1,1:10), increasing=TRUE, strictly=FALSE) [1] TRUE
使用make.index.unique()函数,强制唯一索引。
> x <- xts(1:5, as.POSIXct("2011-01-21") + c(1,1,1,2,3)/1e3) > x [,1] 2011-01-21 00:00:00.000 1 2011-01-21 00:00:00.000 2 2011-01-21 00:00:00.000 3 2011-01-21 00:00:00.002 4 2011-01-21 00:00:00.003 5 > make.index.unique(x) # 增加毫秒级精度,保证索引的唯一性 [,1] 2011-01-21 00:00:00.000999 1 2011-01-21 00:00:00.001000 2 2011-01-21 00:00:00.001001 3 2011-01-21 00:00:00.002000 4 2011-01-21 00:00:00.003000 5
查询xts对象时区。
> x <- xts(1:10, Sys.Date()+1:10) > indexTZ(x) # 时区查询 [1] "UTC" > tzone(x) [1] "UTC" > str(x) An 'xts' object on 2013-11-19/2013-11-28 containing: Data: int [1:10, 1] 1 2 3 4 5 6 7 8 9 10 Indexed by objects of class: [Date] TZ: UTC xts Attributes: NULL
xts给了zoo类型时间序列更多的API支持,这样我们就有了更方便的工具,可以做各种时间序列的转换和变形了。
问题
如何把时间序列可视化?
引言
r-bloggers的一篇博文:plot.xts is wonderful!(http://www.r-bloggers.com/plot-xts-is-wonderful/),让我有动力继续发现xts的强大。xts扩展了zoo的基础数据结构,并提供了更丰富的功能函数。xtsExtra补充库从可视化的角度出发,提供了一个简单而效果非凡的作图函数plot.xts。本节将用plot.xts来演示xts对象的时间序列可视化!
2.3.1 xtsExtra介绍
xtsExtra是xts包的功能补充包,该软件包在Google Summer of Code 2012发布,最终将合并到xts包,不过在笔者写这本书的时候还没有合并。xtsExtra提供的主要功能就是plot.xts()函数。xts::plot.xts()函数与xtsExtra::plot.xts()函数还是有差别的,下面我们就详细介绍其中的差别!
2.3.2 xtsExtra安装
本节使用的系统环境是:
·Win764bit
·R:3.0.1x86_64-w64-mingw32/x64b4bit
注 xtsExtra同时支持Windows 7环境和Linux环境。
由于xtsExtra没有发布到CRAN,我们要从R-Forge下载。
~ R # 启动R 程序 > install.packages("xtsExtra", repos="http://R-Forge.R-project.org") # 从R-Forge 下载xtsExtra 包 > library(xtsExtra) # 加载xtsExtra 包
xtsExtra::plot.xts()函数覆盖了xts::plot.xts()函数。
2.3.3 xtsExtra包的使用
plot.xts()函数的参数列表如下:
> names(formals(plot.xts)) [1] "x" "y" "screens" "layout.screens" "..." [6] "yax.loc" "auto.grid" "major.ticks" "minor.ticks" "major.format" [11] "bar.col.up" "bar.col.dn" "candle.col" "xy.labels" "xy.lines" [16] "ylim" "panel" "auto.legend" "legend.names" "legend.loc" [21] "legend.pars" "events" "blocks" "nc" "nr"
下面画一个简单的时间序列图,如图2-10所示。
图2-10 时间序列
> data(sample_matrix) > sample_xts <- as.xts(sample_matrix) > plot(sample_xts[,1]) > class(sample_xts[,1]) [1] "xts" "zoo"
从图2-10似乎看不出xtsExtra::plot.xts()函数与xts::plot.xts()函数的不同效果。接下来,我们画点稍微复杂的图形。
1.画K线图
下面就来画K线图,默认红白配色,如图2-11所示。
> plot(sample_xts[1:30, ], type = "candles")
图2-11 K线图
画K线图:自定义颜色,如图2-12所示。
> plot(sample_xts[1:30, ], type = "candles", bar.col.up = "blue", bar.col.dn = "violet", candle.col = "green4")
2.对panel配置
画基本面板,如图2-13所示。
> plot(sample_xts[,1:2])
图2-12 自定义颜色的K线图
图2-13 基本面板
画多行面板,如图2-14所示。
> plot(sample_xts[,rep(1:4, each = 3)])
图2-14 多行面板
画自由组合面板,如图2-15所示。
> plot(sample_xts[,1:4], layout.screens = matrix(c(1,1,1,1,2,3,4,4),ncol = 2, byrow = TRUE))
图2-15 自由组合面板
通过画K线图和面板,就能发现plot.xts()函数提供很多种的画图参数设置,让我们画时间序列图可以有更丰富的可视化表示表现形式。
3.对screens配置
画双屏幕显示,每屏幕2条线,如图2-16所示。
> plot(sample_xts, screens = 1:2)
图2-16 双屏显示
画双屏幕显示,指定曲线出现的屏幕和颜色,如图2-17所示。
> plot(sample_xts, screens = c(1,2,1,2), col = c(1,3,2,2))
图2-17 双屏显示且自定义颜色
画双屏幕显示,指定不同的坐标系,如图2-18所示。
> plot(10^sample_xts, screens = 1:2, log= c("","y"))
图2-18 双屏显示,并设置不同坐标系
画双屏幕显示,指定不同的输出图形,如图2-19所示。
> plot(sample_xts[1:75,1:2] - 50.5, type = c("l","h"), lwd = c(1,2))
图2-19 双屏显示且设置不同的输出图形
画多屏幕,并分组显示,如图2-20所示。
> plot(sample_xts[,c(1:4, 3:4)], layout = matrix(c(1,1,1,1,2,2,3,4,5,6), ncol = 2, byrow = TRUE), yax.loc = "left")
图2-20 多屏显示,并多屏分组
4.对events配置
画基本事件分割线,如图2-21所示。
> plot(sample_xts[,1], events = list(time = c("2007-03-15","2007-05-01"), label = "bad days"), blocks = list(start.time = c("2007-03-05", "2007-04-15"), end. time = c("2007-03-20","2007-05-30"), col = c("lightblue1", "lightgreen")))
图2-21 事件分割线
5.双坐标的时间序列
画双坐标视图,如图2-22所示。
> plot(sample_xts[,1],sample_xts[,2])
图2-22 双坐标视图
画双坐标梯度视图,如图2-23所示。
> cr <- colorRampPalette(c("#00FF00","#FF0000")) > plot(sample_xts[,1],sample_xts[,2], xy.labels = FALSE, xy.lines = TRUE, col = cr(NROW(sample_xts)), type = "l")
图2-23 双坐标梯度视图
6.对xts类型转换作图
以ts数据类型作图,如图2-24所示。
> tser <- ts(cumsum(rnorm(50, 0.05, 0.15)), start = 2007, frequency = 12) > class(tser) [1] "ts" > plot(tser)
图2-24 ts数据类型作图
以xts类型作图,自动增加了背景坐标线,如图2-25所示。
> plot.xts(tser)
图2-25 xts类型作图
7.用barplot作图
barplot()函数作条形图,如图2-26所示。
> x <- xts(matrix(abs(rnorm(72)), ncol = 6), Sys.Date() + 1:12) > colnames(x) <- LETTERS[1:6] > barplot(x)
图2-26 barplot图
我们看到xtsExtra::plot.xts()函数提供了强大的作图功能,很容易做出包含丰富元素的时间序列!