如何在ggplot中用NA绘制混合频率系列?

时间:2021-05-17 12:07:36

标签: r ggplot2

我有以下数据框 x

x1 <- data.frame(Date = seq(as.Date("2010-01-01"), 
                           as.Date("2012-12-01"), 
                           by = "month"), 
                TS1 = rnorm(36,0,1), 
                TS2 = rnorm(36,0,1), 
                stringsAsFactors = F)

x2 <- data.frame(Date = seq(as.Date("2010-01-01"), 
                           as.Date("2012-12-01"), 
                           by = "quarter"), 
                TS3 = rnorm(12,0,1), 
                stringsAsFactors = F)

x <- left_join(x1, x2, by = "Date")

x 包含两个月度系列,而一个是季度。

我想用 ggplot 同时绘制所有三个系列。我知道 dualplot 是一种实现方式。然而,它的问题在于它只允许您绘制 2 个混合频率序列。

有人可以帮我解决这个问题吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

请注意,ggplot 需要长格式,因此我们首先使用 tidyr::pivot_longer

接下来,我们可以轻松地绘制 TS1TS2,但 TS3 根本不会绘制,因为它包含缺失值。

一种选择是使用单独的 geom_line 调用绘制缺失的线:

x2 <- x %>%
  tidyr::pivot_longer(cols = c(TS1, TS2, TS3), names_to = "TS") %>%
  mutate(TS = as.factor(TS))

ggplot(x2, aes(x = Date, y = value, group = TS, color = TS)) + 
  geom_line() + 
  geom_line(data = subset(x2, TS == "TS3" & !is.na(value)))

enter image description here

答案 1 :(得分:1)

在这种情况下,ggplot 不必必须将数据转换为长格式(尽管这是一个不错的解决方案,如果您熟悉转换数据,并且特别推荐在以下情况下有很多列或单独的线要绘制)。

为简单起见,尤其是在学习 ggplot 时,我可以提出替代解决方案吗。

TS1TS2 可以很容易地根据日期绘制,因为它们都没有 NA 值。在这里,我们调用 geom_line() 两次,每行一次:

x %>%  
  ggplot()+
  geom_line(aes(Date, TS1), colour = 'red')+
  geom_line(aes(Date, TS2), colour = 'blue')

enter image description here

如果您尝试将第三个 geom_line() 包含在 TS3 中,由于 TS3 的缺失值 (NA),只会绘制原始两条线。一种解决方案是在绘图之前使用 NA 填充数据中的 zoo::na.approx() 值。顾名思义,当您有 zoo::na.approx() 时,NA 能够通过线性插值来近似值。在这种情况下,我假设已知值之间的线性插值适用于绘图(因为 geom_line 无论如何都在做)。查看 ?zoo::na.approx 了解更多详情,包括非线性插值。

zoo::na.approx(TS3, Date, na.rm = FALSE) 可以这样朗读:“我们想根据 TS3 的值来估算 NA 缺失时的值 (Date),如果插值数据中仍有 NA,则保留非 NA 值,我们可以近似。"

x %>%
  mutate(
    TS3 = zoo::na.approx(TS3, Date, na.rm = FALSE)
  ) %>% 
  ggplot()+
  geom_line(aes(Date, TS1), colour = 'red')+
  geom_line(aes(Date, TS2), colour = 'blue')+
  geom_line(aes(Date, TS3), colour = 'green')

enter image description here

请注意,绿线与其他两条线的距离很短(2 个数据点)。这是因为默认情况下,当 zoo::na.approx() 不在两个已知数据点之间时,NA 不会进行插值。这就是我们在进行插值时指定 na.rm = FALSE 的原因。查看帮助页面 ?zoo::na.approx 以获取替代方案(例如重复上次已知的观察)。