Повышение производительности для диаграммы граней граней для больших данных - PullRequest
0 голосов
/ 10 июля 2019

У меня есть несколько временных рядов, и мне нужно построить график рассеяния для каждой комбинации.Поскольку я уже разместил код здесь , с вашей помощью я выяснил, как правильно изобразить все это, используя facet_grid() из пакета ggplot2.

Проблема сейчас в производительности.Пример ниже довольно маленький.Вы можете установить n <- 50000, чтобы касаться меньшего количества данных, которые мне нужно обработать.Я думаю, что наиболее трудоемкой является генерация FACET -Data_Frame со всеми комбинациями и особенно со всеми повторениями.Наконец, вызов сюжета также занимает очень много времени из-за огромного количества линий, через которые я прохожу.nrow(FACET) - это length(df) * length(df) * n, что составляет 5 миллионов в моем реальном реальном случае с n = 50000 и length(df) = 10.

library(tidyverse)
set.seed(214)

n <- 1000
df <- tibble(v1 = runif(n), v2 = runif(n)*0.1 + v1, v3 = runif(n)*0.2 + v2, v4 = runif(n)*0.3 + v3, v5 = runif(n)*0.4 + v4, v6 = runif(n)*0.5 + v5)

C                   <- crossing(w1 = 1:length(df), w2 = 1:length(df))    # Alle Kombinationsmöglichkeiten

FACET_LIST <- lapply(1:nrow(C), function(c) { # c <- 14   C[c,]
  tibble(a1 = unlist(df[, C$w1[c]], use.names = FALSE), 
         a2 = unlist(df[, C$w2[c]], use.names = FALSE), 
         name1 = names(df[, C$w1[c]]),
         name2 = names(df[, C$w2[c]])
  )
})

FACET <- do.call(rbind.data.frame, FACET_LIST)

FACET$name1 <- as_factor(FACET$name1)
FACET$name2 <- as_factor(FACET$name2)

dat_text <- tibble(
  name1 = rep(names(df), each = length(names(df))), 
  name2 = rep(names(df), length(names(df)))
)

p <- ggplot()
p <- p + geom_point(data=FACET, aes(a1, a2), size = 0.5)
p <- p + stat_smooth(data=FACET, aes(a1, a2), method = "lm")
p <- p + facet_grid(vars(name1), vars(name2)) + coord_fixed()
p

Есть ли более эффективный способ передачи требуемой информации в facet_grid() -площадку?Или есть другой способ ускорить мой код?

1 Ответ

1 голос
/ 11 июля 2019

Итак, я провел несколько тестов с n = 50000:

base <- system.time({
  p <- ggplot()
  p <- p + geom_point(data=FACET, aes(a1, a2), size = 0.5)
  print(p)
})

facet <- system.time({
  p <- ggplot()
  p <- p + geom_point(data=FACET, aes(a1, a2), size = 0.5)
  p <- p + facet_grid(vars(name1), vars(name2)) + coord_fixed()
  print(p)
})

# Adding group to stat_smooth, so the number of lines it 
# has to estimate is consistent with the facetted option
smooth <- system.time({
  p <- ggplot()
  p <- p + geom_point(data=FACET, aes(a1, a2), size = 0.5)
  p <- p + stat_smooth(data=FACET, aes(a1, a2, group = interaction(name1, name2)), method = "lm")
  print(p)
})

smooth_facet <- system.time({
  p <- ggplot()
  p <- p + geom_point(data=FACET, aes(a1, a2), size = 0.5)
  p <- p + stat_smooth(data=FACET, aes(a1, a2), method = "lm")
  p <- p + facet_grid(vars(name1), vars(name2)) + coord_fixed()
  print(p)
})

building <- system.time({
  pp <- ggplot_build(p)
})

interpreting <- system.time({
  ppp <- ggplotGrob(pp$plot)
})

library(grid)
drawing <- system.time({
  grid.newpage(); grid.draw(ppp)
})

alternative <- system.time({
  g <- ggplot()
  g <- g + geom_point(data=FACET, aes(a1, a2), size = 0.5, shape = ".")
  g <- g + stat_smooth(data=FACET, aes(a1, a2), method = "lm")
  g <- g + facet_grid(vars(name1), vars(name2)) + coord_fixed()
  print(g)
})

Это были результаты:

rbind(base, facet, smooth, smooth_facet, building, interpreting, drawing, alternative)
             user.self sys.self elapsed user.child sys.child
base              8.34    30.96   39.44         NA        NA
facet             8.56    30.48   39.12         NA        NA
smooth           10.00    31.14   41.18         NA        NA
smooth_facet     10.14    31.50   41.73         NA        NA
building          2.59     0.42    3.03         NA        NA
interpreting      5.08     0.61    5.76         NA        NA
drawing           5.13    30.23   35.39         NA        NA
alternative       7.58     8.23   15.86         NA        NA

Что подсказывает мне, что это не код медленного ggplot, это либо код рисования, либо тот факт, что вам нужно рисовать много точек.

Однако может показаться, что вы можете сократить время более чем наполовину, не используя округленные точки, а используя shape = "." в выражении geom_point() (как в «альтернативном» тесте). В любом случае, вы, вероятно, перепланируете точки. Вот как это выглядит:

enter image description here

...