五、描述时间序列数据的可视化图形
#本节演示需要载入的软件包
library(ggridges)
library(lubridate)
library(ggrepel)
library(ggplot2)
library(dplyr)
library(plotly)
library(hrbrthemes)
library(readxl)
library(dygraphs)
cpi <- read_xls("../cpi.xls")
cpi$date <- ymd(cpi$date) #定义列表日期格式
str(cpi) #显示数据集字段类型
## tibble [72 × 4] (S3: tbl_df/tbl/data.frame)
## $ date : Date[1:72], format: "2016-01-01" "2016-02-01" ...
## $ cpi.val : num [1:72] 1.8 2.3 2.3 2.3 2 1.9 1.8 1.3 1.9 2.1 ...
## $ cpi.city : num [1:72] 1.8 2.3 2.3 2.3 2 1.9 1.8 1.4 2 2.2 ...
## $ cpi.countryside: num [1:72] 1.5 2.2 2.2 2.4 2.1 1.9 1.5 1 1.6 1.8 ...
先前我们讨论过相关变量如何绘制散点图,即将两个变量进行对比生成的图形。如果两个变量中有一个被认为是时间序列时,就会出现一类特殊的数据类型,将这类带有时间序列的数据称之为时间序列数据。现在数据点有一个固有的顺序,可以按时间的顺序排列这些点,想要可视化这个时间序列,一般使用点图或是线图来实现。然而,线形图或者折线图并不局限于时间序列。当一个变量被定义为一个顺序变量时,这类可视化图形是适用的。此外,时间序列可能同时控制多个变量的顺序时,可以按照时间序列统一维度下的以多条线图和散点图来展示数据,一般情况下,如果数据有明显的趋势特征时,这类图形是适用的。
(一)单变量时间序列数据可视化
CPI 是居民消费价格指数(Consumer Price Index)的简称。居民消费价格指数是一个反映居民家庭一般所购买的消费商品和服务价格水平变动情况的宏观经济指标,是度量一组代表性消费商品及服务项目的价格水平随时间而变动的相对数,是用来反映居民家庭购买消费商品及服务的价格水平的变动情况。
居民消费价格统计调查的是社会产品和服务项目的最终价格,一方面同人民群众的生活密切相关,同时在整个国民经济价格体系中也具有重要的地位。它是进行经济分析和决策、价格总水平监测和调控及国民经济核算的重要指标。其变动率在一定程度上反映了通货膨胀或紧缩的程度。一般来讲,物价全面地、持续地上涨就被认为发生了通货膨胀。下面示例是近几年的 CPI 涨跌情况(见图 6-2-51)。
ggplot(cpi, aes(date, cpi.val)) +
geom_point(color = "#0072B2") +
geom_point(color = "white", fill = "#0072B2", shape = 21, size = 2) +
scale_y_continuous(limits = c(-1, 6) , expand = c(0, 0), name = "CPI/%") +
scale_x_date(name = "year")+
theme_bw()+
theme(plot.margin = margin(5, 3, 3, 3))
图 6-2-51 时间序列的散点图
然而,图 6-2-51 与前面内容讨论的散点图有一个重要区别。在这个点图中,y 的变化是随着时间序列 x 轴有均匀间隔,点与点之间有明确的顺序。每个点只有一个左邻和一个右邻的点(除了最左和最右的点,每个点只有一个邻点)。通过用线连接相邻的点来从视觉上观察这个顺序,把这样的图称为线形图,如图 6-2-52 所示。
ggplot(cpi, aes(date, cpi.val)) +
geom_line(size = 0.5, color = "#0072B2") +
geom_point(color = "white", fill = "#0072B2", shape = 21, size = 2) +
scale_y_continuous(limits = c(-1, 6), expand = c(0, 0),
name = "CPI/%") +
scale_x_date(name = "year") +
theme_bw() +
theme(plot.margin = margin(7, 7, 3, 1.5))
图 6-2-52 时间序列的线形图
使用线来表示时间序列是普遍的做法,若只显示线不显示点,这类图称之为折线图。没有点,该图更强调数据的整体趋势。没有点的图形在视觉上看起来更自然。一般来说,时间序列越密集,用点显示单个观察的重要性就越低。对于该数据集,使用折线图来展示,如图6-2-53 所示。
ggplot(cpi, aes(date, cpi.val)) +
geom_line(color = "#0072B2", size = 0.7) +
scale_y_continuous(limits = c(-1, 6), expand = c(0, 0),
name = "CPI/%") +
scale_x_date(name = "year") +
theme_bw() +
theme(plot.margin = margin(7, 7, 3, 1.5))
图 6-2-53 时间序列的折线图
接下来,用纯色填充曲线下方的区域。这类图形类似于面积图,进一步强调了数据的总体趋势。但是,这种可视化只有在 y 轴从零开始时才有效,如果有小于 0 的情况,显示的图形会缺失这部分图,如图 6-2-54 所示。此外,每个时间点的阴影区域的高度代表了该时间点的数据值大小。
图 6-2-54 时间序列的面积图
ggplot(cpi, aes(date, height = cpi.val, y =0)) +
geom_ridgeline(color = "#0072B2",alpha=0.6,fill = "#0072B240", size = 0.40) +
scale_y_continuous(limits = c(-1, 6), expand = c(0, 0),
name = "CPI/%") +
scale_x_date(name = "year")+
theme(plot.margin = margin(4,4, 3, 3))+
theme_bw()
(二)多变量时间序列可视化
如果同时展示相同时间维度上的多个变量,必须更加慎重地选择绘制的图形,因为该图形可能变得混乱或难以阅读。例如,如果想要显示每月 CPI 外,还要同时展示城市和乡村的CPI,这时散点图就不是一个好策略,因为各个时间点的变量会相互影响和重叠,视觉效果不佳,如图 6-2-55 所示。如果用线连接点可以较好地缓解这个问题,如图 6-2-56 所示。
p <- ggplot(cpi)
p+ geom_point(mapping=aes(x=date, y = cpi.val, color = "CPI"),size = 2) +
geom_point(mapping=aes(x=date, y = cpi.city, color = "CPI City"),size =2) +
geom_point(mapping=aes(x=date, y= cpi.countryside,
color = "CPI Countryside"),size = 2) +
scale_y_continuous(limits = c(-1, 6), expand = c(0, 0),name = "CPI/%")+
scale_x_date( name = "year", expand = expand_scale(mult = c(0, 0))) +
scale_color_manual(values = c("#0072b2", "#D55E00", "#009e73")) +
scale_fill_manual(values = c("#0072b2", "#D55E00", "#009e73")) +
scale_shape_manual(values = c(21, 22, 23), name = NULL) +
theme_bw() +
theme(axis.text.y.right = element_text(margin = margin(0, 0, 0, 0)),
plot.margin = margin(14, 7, 3, 1.5))
图 6-2-55 多变量时间序列散点图
p <- ggplot(cpi)
p + geom_line(mapping = aes(x = date, y = cpi.val, color = "cpi.val"),size = 0.8) +
geom_point(mapping = aes(x = date, y = cpi.val, color = "cpi.val"),size = 3) +
geom_line(mapping = aes(x = date, y =cpi.city, color = "cpi.city"),size = 0.8)+
geom_point(mapping = aes(x = date, y = cpi.city, color = "cpi.city"),size =3) +
geom_line(mapping = aes(x = date, y = cpi.countryside,
color = "cpi.countryside"),size = 0.8)+
geom_point(mapping = aes(x = date, y = cpi.countryside,
color = "cpi.countryside"),size = 3) +
scale_y_continuous(limits = c(-1, 6), expand = c(0, 0),name = "CPI/%")+
scale_x_date( name = "year", expand = expand_scale(mult = c(0, 0))) +
scale_color_manual( values = c("#0072b2", "#D55E00", "#009e73")) +
scale_fill_manual(values = c("#0072b2", "#D55E00", "#009e73")) +
scale_shape_manual(values = c(21, 22, 23), name = NULL) +theme_bw() +
theme(axis.text.y.right = element_text(margin = margin(0, 0, 0, 0)),
plot.margin = margin(14, 7, 3, 1.5))
图 6-2-56 多变量时间序列线形图
如果消除了图 6-2-56 中的单个点,结果更加精简和易于阅读,如图 6-2-57 所示。
p <- ggplot(cpi)
p + geom_line(mapping = aes(x = date, y = cpi.val, color = "CPI"),size = 1) +
geom_line(mapping = aes(x = date, y = cpi.city, color = "CPI City"),size =1) +
geom_line(mapping = aes(x = date, y = cpi.countryside,
color = "CPI Countryside"),size = 1) +
scale_y_continuous(limits = c(-1, 6), expand = c(0, 0),name = "CPI/%")+
cale_x_date( name = "year", expand = expand_scale(mult = c(0, 0)))+
scale_color_manual(values = c("#0072b2", "#D55E00", "#009e73")) +
scale_fill_manual(values = c("#0072b2", "#D55E00", "#009e73"),name = NULL) +
scale_shape_manual(values = c(21, 22, 23), name = NULL) +
coord_cartesian(clip = "off") +
theme_bw() +
theme(legend.position = "none")
theme(axis.line.y.right = element_blank(),axis.ticks.y.right = element_blank(),
axis.text.y.right = element_text(margin = margin(0, 0, 0, 0)),
plot.margin = margin(4, 4, 3, 3))
图 6-2-57 三个变量的时间序列折线图
折线图不仅仅用于时间序列,只要数据点具有反映在沿 x 轴显示的变量中的自然顺序,就适用,以便相邻点可以用线连接。例如,测量燕麦产量和施肥量的增加之间的变化关系。折线图突出考虑了三个燕麦品种的剂量反应曲线如何具有相似形状,但在没有施肥的情况下起点不同(即某些品种的产量自然高于其他品种)。如图 6-2-58 所示,剂量-反应曲线显示了施肥后燕麦品种的平均产量。粪肥是氮的来源,燕麦产量通常会随着可用氮的增加而增加。
MASS::oats %>%
mutate(N = 1*as.numeric(sub("cwt", "", N, fixed = TRUE))) %>%
group_by(N, V) %>%
summarize(mean = 20 * mean(Y)) %>%
mutate(variety = ifelse(V == "Golden.rain", "Golden Rain", as.character(V))) ->
oats_df
oats_df$variety <- factor(oats_df$variety,
levels = c("Marvellous", "Golden Rain", "Victory"))
ggplot(oats_df,
aes(N, mean, color = variety, shape = variety, fill = variety)) +
geom_line(size = 0.75) +
geom_point(color = "white", size = 2.5) +
scale_y_continuous(name = "mean yield (lbs/acre)") +
scale_x_continuous(name = "manure treatment (cwt/acre)") +
scale_shape_manual(values = c(21, 22, 23)) +
scale_color_manual(values = c("#0072b2", "#D55E00", "#009e73")) +
scale_fill_manual(values = c("#0072b2", "#D55E00", "#009e73")) +
coord_cartesian(clip = "off") +
theme_bw() +
theme(legend.title.align = 0.5)
图 6-2-58 三个变量的折线图
另外,R 语言的 dygraphs 函数提供了一个网页上动态展示个性化的时间序列图形,如图6-2-59 所示。
p <- cpi %>%
ggplot( aes(x=date, y=cpi.val)) +
geom_area(fill="#0072B2", alpha=0.6) +
geom_line(color="#0072B2",size=0.2) +
scale_x_date(name="year")+ #相当于 xlab("year")
ylab("CPI/%") +
theme_ipsum()+
theme_dviz_hgrid()
p <- ggplotly(p)
p
图 6-2-59 时间序列的动态图