简介
最近在科研论文中需要通过可视化形式展示时间序列的交叉验证场景。从其他学者的文章中看到以下图形。
该图非常直观说明时间序列交叉验证的过程。其中蓝色点数据用于训练模型,黄色点数据用于测试数据。作为一名 R 语言爱好者,小编打算参照这种可视化形式,基于 ggplot2 包绘制下,并放到自己论文中。
初体验
棒棒图的简单绘制其实小编以前提及过,见: R可视乎|克利夫兰点图系列。当然也可以使用 ggpubr 包绘制:使用 ggpubr 包制图。但是最多只能绘制到这种程度:
而我的需求和简单的棒棒图不同。我需要很多点的连接,并在图中各个位置的用散点表示。
头脑风暴
经过小编的思考,我打算直接使用 ggplot2[1] 包进行绘制。具体思路如下:
- 使用
expand.grid()
构造每个点的数据。 - 添加新列(
class
)标记不同位置的颜色(蓝色:训练数据,黄色:测试数据,灰色:未使用的数据)。 - 利用几何对象(
geom_segment()
:线段,geom_point()
:散点)绘制对应图形。 - 细节修改,包括:主题,图例,坐标轴等。
接下来根据该思路,小编复现结果如下
从构思到绘图花了一个小时!太慢了。主要是构思和数据构造花了比较过的时间。接下来,给出分步代码。汇总代码见文末或者我的 Github[2]。
https://github.com/liangliangzhuang
教程
创建数据
使用 expand.grid()
构造每个点的数据。前6行数据如下:
dim1 = c(25,11) # 第一项x轴,第二项y轴 combinations <- expand.grid(1:dim1[1],1:dim1[2]) dat = cbind(1:dim(combinations)[1],combinations) colnames(dat) = c("id","value1","value2")
添加新列(class
),其中,0表示未使用的数据;1表示训练数据,2表示测试数据。此时,前6行数据如下:
dis1 = 10; dis2 = 4 # dis1训练点个数,dis2测试集个数 dat$class = 0 for(i in 1:dim1[2]){ dat$class[((dim1[1]+1)*(i-1) + 1):((dim1[1]+1)*(i-1) + dis1)] = 1 dat$class[((dim1[1]+1)*(i-1) + dis1 + 1):((dim1[1]+1)*(i-1) + dis1 + dis2 - 1)] = 2 }
绘图
基于前面的数据进行绘图。利用几何对象(geom_segment()
:线段,geom_point()
:散点)绘制对应图形。
ggplot(data = dat,aes(value1,value2)) + geom_segment(data = dat[dat$value1!=dim1[1], ],aes(x=value1, xend=value1+1, y=value2, yend=value2),color="grey",size=1) + geom_point(aes(color=as.factor(class)), size=3, shape = 19)
此时,图形大致已经满足要求,接下来进行细节修改。在上面的代码下添加以下代码。其中,颜色修改(scale_color_manual()
),y 轴转置(scale_y_reverse()
),主题设置(theme_bw()
,theme()
)。具体细节就不多说啦!可以看我的 B 站 2 小时的 ggplot 入门教程。
scale_color_manual(values = c("grey","#2F6DA3","#CC9034"),name = "Class",labels = c("Nothing","Window","Forecasting horizon")) + scale_y_reverse(breaks = seq(1,12,3)) + scale_x_continuous(breaks = c(1,10,20,30)) + xlab("Time") + ylab("Window number") + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank(), legend.position = "bottom", axis.line = element_line(colour = "black"))
代码汇总
# 加载包 library(ggplot2) library(dplyr) # 创建数据 dim1 = c(25,11) # 第一项x轴,第二项y轴 combinations <- expand.grid(1:dim1[1],1:dim1[2]) dat = cbind(1:dim(combinations)[1],combinations) colnames(dat) = c("id","value1","value2") head(dat) # 创建新列 dis1 = 10; dis2 = 4 # dis1训练点个数,dis2测试集个数 dat$class = 0 for(i in 1:dim1[2]){ dat$class[((dim1[1]+1)*(i-1) + 1):((dim1[1]+1)*(i-1) + dis1)] = 1 dat$class[((dim1[1]+1)*(i-1) + dis1 + 1):((dim1[1]+1)*(i-1) + dis1 + dis2 - 1)] = 2 } head(dat) # 绘图 ggplot(data = dat,aes(value1,value2)) + geom_segment(data = dat[dat$value1!=dim1[1], ],aes(x=value1, xend=value1+1, y=value2, yend=value2),color="grey",size=1) + geom_point(aes(color=as.factor(class)), size=3, shape = 19) + scale_color_manual(values = c("grey","#2F6DA3","#CC9034"),name = "Class",labels = c("Nothing","Window","Forecasting horizon")) + scale_y_reverse(breaks = seq(1,12,3)) + scale_x_continuous(breaks = c(1,10,20,30)) + xlab("Time") + ylab("Window number") + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank(), legend.position = "bottom", axis.line = element_line(colour = "black"))
小编有话说
- 这是小编科研过程中的一个绘图笔记,希望能帮助到你(代码开源)。
- 如果你觉得有帮助到你,欢迎一键三连~如果有更好的方法,欢迎留言分享~
- 最近小编在申请 CSC 出国留学项目,祝我有个好结果吧,害。
参考资料
[1]
ggplot2: https://ggplot2.tidyverse.org/reference/ggplot.html
[2]