ggplot2绘制高频时间序列

Posted by Elsa.Liu & Bruce Zhao on June 6, 2016

Estimated reading time: 11 minutes. {R} [ggplot2]

目录

{: .no_toc}

开始

我们常常要利用R来绘制简单的时序图,当时间序列间隔以天为单位时,我们可以利用ts()函数将数据非常方便的转换成R可以识别的时间对象,然后在利用plot.ts()函数绘制就行了。 但如果我们的时间序列是以更高频的形式呈现,那么简单粗暴的ts()就显得不够用了,因此今天介绍一下如何绘制高频数据的时序图。 R中除了有Date这种时间格式之外,还有许多姿势任君挑选(手动微笑),下面介绍三种不同的时间格式。

转换成xts格式

f1<-file.choose()
x<-read.csv(f1,header=T,row.names = 1)
head(x)
#>                count
#> 2014/8/25 0:00    72
#> 2014/8/25 5:00    56
#> 2014/8/25 6:00  1410
#> 2014/8/25 7:00  5093
#> 2014/8/25 8:00  5257
#> 2014/8/25 9:00  3771

例子中的数据是每天不同时段的车流量大小。

这里需要注意的技巧就是读取数据时设置参数’row.names=1’,意思是将第一列作为数据的‘rownames’,因此可以看到’x’读入之后数据只有一列,其实本来还有一列是时间。可以理解成将时间戳作为了’count’的一个标签。

x_xts<-as.xts(x)
plot.xts(x_xts)

xts作为zoo的扩充,提供了一系列针对时间序列相关的函数。

xts is an R package offering a number of functionalities to work on time-indexed data. xts extends zoo, another popular package for time-series analysis.

转换成zoo格式

x_zoo<-zoo(x,order.by = as.factor(rownames(x)))
plot.zoo(x_zoo)

这里的’zoo()’函数与’as.xts’类似,也是给’count’变量赋予时间标签,’order.by’参数就是指定具体的时间标签索引。

不知道大家有没有疑问,如果出现相同的日期怎么办? 为什么order.by为factor的数据类型?

转换成POSIXct格式

但是私以为上面两幅图还是挺丑的(对黑白没有爱),出于对颜值的追求,是时候祭出绘图包中的神器ggplot2了。但是首先我们要把文本格式的时间转换成ggplot能够识别的对象。

x$time<-strptime(rownames(x), "%Y/%m/%d %H:%M")
# as.POSIXct(rownames(head(x)),format="%Y/%m/%d %H:%M")

这里’strptime()‘的作用就是将各种乱七八糟文本结构的时间数据,转换成ggplot能识别的标准时间格式,需要注意的是第一个参数是我们所拥有的高频数据的时间列,第二个参数是这个时间列的具体写法,如果你的时间列写法是’16-5-29 16:05:00’,那么我们第二个参数设置就是’y%-m%-d% %H:%M:%S’。接下来就可以愉快的画图了。

注:x_xts 的class为xts,其index(x_xts)为“POSIXct” “POSIXt” ,于是就可以省去了转换这一步。相应的画图代码为:ggplot(x_xts,aes(x=index(x_xts),y=count))+geom_line()

ggplot画图

ggplot(x,aes(x=time,y=count))+geom_line()

进一步细化,不同日期标注不同色块?

解决办法一

# 参考有关教程得到的方案:

#添加一个新的data.frame
day <- unique(strptime(x$time,format = "%Y-%m-%d"))
time_df <- data.frame(min=day,
                      max=day+60*60*24,
                      fill=as.factor(as.character(day)))

#一定要注意那两个 NULL,少了就会报错。
ggplot(data=x,aes(x=time,y=count))+
  geom_rect(aes(NULL,NULL,
                xmin=min,
                xmax=max,
                ymin=min(x$count),
                ymax=max(x$count),
                fill=fill),data=time_df) + 
  geom_line()


#通过上面的例子我相信你已经理解了图层叠加的原理了,
#下面这个例子更直接
ggplot() + geom_rect(data=time_df,
                     aes(xmin=min,xmax=max,
                         ymin=min(x$count),ymax=max(x$count),
                         fill=fill),colour="white") + 
  geom_line(data=x, aes(x=time,y=count))

解决办法二

小赵摸索出来的方法:


#对数据整体修改,添加变量
x$day<-strptime(x$time,format = "%Y-%m-%d")

#先线再色块, fill 为连续变量,图层叠加原理 ggplot(x,aes(x=time,y=count))+ geom_line()+ geom_rect(aes(xmin=day, xmax=day + 606024, #一天,单位秒 ymin=min(count), ymax=max(count), fill=day),colour="white",alpha=0.1)


#先色块再线 ,fill 为factor
##美化
windowsFonts(myfont=windowsFont("微软雅黑"))

ggplot(x,aes(x=time,y=count)) + geom_rect(aes(xmin=day, xmax=day + 606024, ymin=min(count), ymax=max(count), fill=as.factor(as.character(day))),colour="white")+ geom_line() + labs(title="测试时间格式",fill="日期") + theme(title=element_text(family = ‘myfont’,face = "bold"), text=element_text(family = ‘myfont’))

总结

  1. 在用xts或者zoo的时候,碰到了好多坑。下次会专门写一篇处理时间格式的数据
  2. 在用ggplot画图的时候,坐标轴的类型一定要是一样的!比如这次横坐标的time是数据类型为POSIXct,如果用as.Date后的类型的话会报错了
  3. 通过这个例子更深入理解了图层语法

更新

这篇当时写的时候也是刚刚接触ggplot画时间序列的图,在后面的不断学习中又get到新的技能,所以准备补充更新一下。

关于调整x轴时间间隔与标签

scale_x_datetime(date_breaks = "5 mins",
				 date_labels = %H:%M",
				 date_minor_breaks = "1 min")

这里的可以写成10 secs,或者1 hour等自定义的时间间隔。

关于zooming

# without clipping
coord_cartesian(xlim=c(0,100),ylim=c(10,20))

# with clipping
xlim(0,100) + ylim(10,20)
# or
scale_x_continous(limits=c(0,100) +
scale_y_continous(limits=c(10,20)

不定期更新中