Используйте внешний вместо expand.grid

Я ищу как можно большую скорость и остаюсь на базе, чтобы делать то, чтоexpand.grid делает. я использовалouter для аналогичных целей в прошлом создавался вектор; что-то вроде этого:

<code>v <- outer(letters, LETTERS, paste0)
unlist(v[lower.tri(v)])
</code>

Бенчмаркинг показал мне, чтоouter может быть значительно быстрее, чемexpand.grid но на этот раз я хочу создать две колонки, какexpand.grid (все возможные комбинации для 2 векторов), но мои методы сouter на этот раз не сравнивайте так быстро с внешним.

Я надеюсь взять 2 вектора и создать максимально возможную комбинацию из двух столбцов (думаю,outer может быть маршрут, но я широко открыт для любого базового метода.

Здесьexpand.grid метод иouter метод.

<code>dat <- cbind(mtcars, mtcars, mtcars)

expand.grid(seq_len(nrow(dat)), seq_len(ncol(dat)))

FOO <- function(x, y) paste(x, y, sep=":")
x <- outer(seq_len(nrow(dat)), seq_len(ncol(dat)), FOO)
apply(do.call("rbind", strsplit(x, ":")), 2, as.integer)
</code>

Микробенчмаркинг-шоуouter медленнее:

<code>#     expr      min        lq    median        uq      max
# EXPAND.G  812.743  838.6375  894.6245  927.7505 27029.54
#    OUTER 5107.871 5198.3835 5329.4860 5605.2215 27559.08
</code>

Я думаю мойouter использование медленное, потому что я не знаю, как использоватьouter напрямую создать вектор длины 2, который я могуdo.call('rbind' все вместе. Я должен замедлитьpaste и медленный сплит. Как я могу сделать это сouter (или другие методы вbase) таким образом, что это быстрее, чемexpand grid?

EDIT: Adding the microbenchmark results.

**

<code>Unit: microseconds
      expr     min       lq  median      uq       max
1   ERNEST  34.993  39.1920  52.255  57.854 29170.705
2     JOHN  13.997  16.3300  19.130  23.329   266.872
3 ORIGINAL 352.720 372.7815 392.377 418.738 36519.952
4    TOMMY  16.330  19.5960  23.795  27.061  6217.374
5  VINCENT 377.447 400.3090 418.505 451.864 43567.334
</code>

**

enter image description here

 Tyler Rinker04 мая 2012 г., 15:45
Да, только что. Это действительно самый быстрый.
 John04 мая 2012 г., 08:41
Тайлер, ты не против добавить мой метод в список тестов? Это должно быть вдвое быстрее, чем самый быстрый, который у вас здесь есть.

Ответы на вопрос(4)

Решение Вопроса

С помощьюrep.int:

expand.grid.alt <- function(seq1,seq2) {
  cbind(rep.int(seq1, length(seq2)),
        c(t(matrix(rep.int(seq2, length(seq1)), nrow=length(seq2)))))
}

expand.grid.alt(seq_len(nrow(dat)), seq_len(ncol(dat)))

В моем компьютере это как в 6 раз быстрее, чемexpand.grid.

 02 мая 2012 г., 03:07
@TylerRinker Осторожно, в моей функции была ошибка!nrow аргумент был неверным. Я исправил это сейчас.
 22 июл. 2013 г., 22:22
@ErnestA Я добавил скобки в крайнем правом углу последней строки кода, затем мне пришлось добавить еще текст, прежде чем редактирование могло быть отправлено.
 Tyler Rinker02 мая 2012 г., 02:22
Я был очень скептичен, но это очень быстро. Хороший ответ. Я думаю, что внешний подход не был подходом, который я должен был использовать. Я разместил результаты микробенчмаркинга на машине WIn 7 выше.

Вы можете создать две колонки отдельно.

library(microbenchmark)
n <- nrow(dat)
m <- ncol(dat)
f1 <- function()   expand.grid(1:n, 1:m)
f2 <- function()   
  data.frame( 
    Var1 = as.vector(outer( 1:n, rep(1,m) )),
    Var2 = as.vector(outer( rep(1,n), 1:m ))
  )
microbenchmark( f1, f2, times=1e6 )
# Unit: nanoseconds
#   expr min  lq median  uq    max
# 1   f1  70 489    490 559 168458
# 2   f2  70 489    490 559 168597
 Tyler Rinker02 мая 2012 г., 02:21
Спасибо за ответ. Вы решили мою внешнюю проблему, и обучение было потрясающим. Подход Эрнеста очень быстр, намного быстрее, чем внешний подход.

rep.int не совсем завершен. Это не просто самый быстрый в наиболее распространенном случае, потому что вы можете передавать векторы для аргумента time, как в случае сrep, Вы можете использовать его просто для обеих последовательностей, сокращая время еще на 40% по сравнению с Томми.

expand.grid.jc <- function(seq1,seq2) {
    cbind(Var1 = rep.int(seq1, length(seq2)), 
    Var2 = rep.int(seq2, rep.int(length(seq1),length(seq2))))
}
 Tyler Rinker02 мая 2012 г., 14:53
в текущем состоянии ваш код выдает ошибку. Я думаю, что где-то отсутствует скобка, но я не могу понять, где.
 02 мая 2012 г., 18:16
+1 Круто! Этоshouldn't будь быстрее, чем у меня, но это, безусловно, так :-)rep необходимо улучшить, как он обрабатываетeach аргумент ...
 12 мар. 2019 г., 15:50
Что если у нас есть только один список для передачи в качестве переменной и мы хотим все возможные комбинации? например expand.grid_jc (input_list)
 15 мар. 2019 г., 15:25
Я не уверен, что вы имеете в виду. Если у вас есть список с двумя векторами, вы можете просто использовать do.call (expand.grid.jc, myList). В противном случае я не уверен, как этот вопрос имеет смысл. Возможно, расширить его до полного CrossValidated вопрос?
 02 мая 2012 г., 19:28
да, Томми, это должно ... Я на самом деле думаю, что expand.grid использует что-то наподобие того, что я написал внутренне ... это просто медленно из-за проверки ошибок и надежности.

... это может быть немного быстрее, хотя:

expand.grid.alt2 <- function(seq1,seq2) {
  cbind(Var1=rep.int(seq1, length(seq2)), Var2=rep(seq2, each=length(seq1)))
}

s1=seq_len(2000); s2=seq_len(2000)
system.time( for(i in 1:10) expand.grid.alt2(s1, s2) ) # 1.58
system.time( for(i in 1:10) expand.grid.alt(s1, s2) )  # 1.75
system.time( for(i in 1:10) expand.grid(s1, s2) )      # 2.46
 02 мая 2012 г., 10:49
@ Томми, я пошел на все, чтобы избежатьrep(... each=) потому что я предполагал, что это будет медленнее. Фактически это не так.
 02 мая 2012 г., 10:52
@TylerRinker Не стесняйтесь снять мой ответ, поскольку есть другие решения, которые работают быстрее. Совершенно никаких проблем!
 02 мая 2012 г., 04:43
@TylerRinker - Да, я сделал. Так что теперь вы можете чувствовать себя совершенно спокойно ;-)
 Tyler Rinker02 мая 2012 г., 04:13
Очень приятно, определенно увеличение скорости по сравнению с Эрнестом. +1 Я собираюсь сохранить чек на Эрнесте, хотя это быстрее, потому что я уже дал чек, и я чувствую себя смешно по поводу переназначения. Мне было бы легче, если бы вы основали свой ответ на его ответе :) Могу ли я спросить, если вы сделали?

Ваш ответ на вопрос