読者です 読者をやめる 読者になる 読者になる

時系列データの積み重ねグラフ

R zoo ggplot2

こういう、複数のデータ系列を持つ時系列データがあるとします。で、このデータを使って積み重ねグラフを描きたいとします。

library(dplyr)
library(lubridate)

set.seed(1)
d <- data_frame(time  = seq(ymd_h(2015042400), ymd_h(2015042401), by = "min"),
                value1 = 10 + runif(length(time)),
                value2 = 10 + runif(length(time)),
                value3 = 10 + runif(length(time)))

やることはひとつ。tidyにしてggplot2を使うだけです。単純明快です。

library(tidyr)
library(ggplot2)
library(gridExtra)

d_tidy <- d %>%
  gather(type, value, -time) %>%
  arrange(time)

p <- ggplot(d_tidy, aes(x = time, y = value))
p1 <- p + geom_line(aes(colour = type)) + ylim(c(0, NA))
p2 <- p + geom_area(aes(fill = type), position = "stack")
grid.arrange(p1, p2)

f:id:yutannihilation:20150424230446p:plain

現実は甘くない

しかし、たとえば一定間隔でセンサーから値を取ってDBに入れる、みたいなパターンを想像すると、こんなにキレイに同時刻にデータを観測できているとは限りません。現実に即して、timeにずれを付け加えてみます。

set.seed(1)
d_fuzzy <- d_tidy %>%
  mutate(time = time + seconds(round(runif(n(), min = -15, max = 15))))

で、これをさっきと同じノリで積み重ねてみると、、

p <- ggplot(d_fuzzy, aes(x = time, y = value))
p1 <- p + geom_line(aes(colour = type)) + ylim(c(0, NA))
p2 <- p + geom_area(aes(fill = type), position = "stack")
grid.arrange(p1, p2)

f:id:yutannihilation:20150424231758p:plain

なんと、積み重なってません。あれ、postion = "stack"を忘れてる??と思って二度見しましたが、そんなことはありません。

積み重ねグラフは、X軸の値が完全に同じじゃないと積み重ねられないので、少しでもずれがあるとダメです。

データを補間する

そんなときはapprox()でデータを補完するといいっぽいです。approx()xoutというパラメータで補間してほしい場所を指定できます。ここに、きれいな刻みの時刻を指定しておきます。

補間はデータ系列ごとにやらないとだめなので、いちどsplit()しないとだめそうです。

d_split <- split(d_fuzzy, d_fuzzy$type)
tics <- seq(ymd_h(2015042400), ymd_h(2015042401), by = "min")

res <- list()

for(t in names(d_split)) {
  tmp <- d_split[[t]]
  res[[t]] <- as_data_frame(approx(x = tmp$time, y = tmp$value, xout = tics, rule = 2))
  res[[t]]$type <- t
}

d_tidy_at_last <- bind_rows(res)

p <- ggplot(d_tidy_at_last, aes(x = x, y = y))
p1 <- p + geom_line(aes(colour = type)) + ylim(c(0, NA))
p2 <- p + geom_area(aes(fill = type), position = "stack")
grid.arrange(p1, p2)

f:id:yutannihilation:20150424235445p:plain

うーん、こんな感じでいいんでしょうか。。

もうちょっときれいな書き方をだれか教えてください。

参考にしたサイト

大仏様ありがとうございます。