Подтвердить что ты не робот

Эффективно реплицируем матрицы в R

У меня есть матрица и ищут эффективный способ ее повторения n раз (где n - количество наблюдений в наборе данных). Например, если у меня есть матрица A

A <- matrix(1:15, nrow=3)

то я хочу получить результат формы

rbind(A, A, A, ...) #n times.

Очевидно, что существует множество способов построения такой большой матрицы, например, с использованием цикла for или apply или подобных функций. Однако вызов функции "матрица-репликация" происходит в самом ядре моего алгоритма оптимизации, где он называется десятками тысяч раз в течение одного запуска моей программы. Поэтому петли, функции типа приложения и все, что с ними похоже, недостаточно эффективны. (Такое решение в основном означало бы, что цикл над n выполняется десятки тысяч раз, что, очевидно, неэффективно.) Я уже пытался использовать обычную функцию rep, но не нашел способ упорядочить вывод rep в матрице желаемого формата.

Решение do.call("rbind", replicate(n, A, simplify=F)) также слишком неэффективен, потому что rbind используется слишком часто в этом случае. (Затем около 30% от общей продолжительности выполнения моей программы тратится на выполнение rbinds.)

Кто-нибудь знает лучшее решение?

4b9b3361

Ответ 1

Еще два решения:

Первая - это модификация примера в вопросе

do.call("rbind", rep(list(A), n))

Вторая включает в себя разворачивание матрицы, ее репликацию и повторную сборку.

matrix(rep(t(A),n), ncol=ncol(A), byrow=TRUE)

Поскольку эффективность - это то, что было запрошено, необходим бенчмаркинг

library("rbenchmark")
A <- matrix(1:15, nrow=3)
n <- 10

benchmark(rbind(A, A, A, A, A, A, A, A, A, A),
          do.call("rbind", replicate(n, A, simplify=FALSE)),
          do.call("rbind", rep(list(A), n)),
          apply(A, 2, rep, n),
          matrix(rep(t(A),n), ncol=ncol(A), byrow=TRUE),
          order="relative", replications=100000)

который дает:

                                                 test replications elapsed
1                 rbind(A, A, A, A, A, A, A, A, A, A)       100000    0.91
3                   do.call("rbind", rep(list(A), n))       100000    1.42
5  matrix(rep(t(A), n), ncol = ncol(A), byrow = TRUE)       100000    2.20
2 do.call("rbind", replicate(n, A, simplify = FALSE))       100000    3.03
4                                 apply(A, 2, rep, n)       100000    7.75
  relative user.self sys.self user.child sys.child
1    1.000      0.91        0         NA        NA
3    1.560      1.42        0         NA        NA
5    2.418      2.19        0         NA        NA
2    3.330      3.03        0         NA        NA
4    8.516      7.73        0         NA        NA

Таким образом, самым быстрым является вызов raw rbind, но предполагается, что n фиксирован и известен заранее. Если n не фиксировано, то самым быстрым является do.call("rbind", rep(list(A), n). Это были для матрицы 3x5 и 10 повторений. Матрицы различного размера могут давать разные порядки.

EDIT:

При n = 600 результаты находятся в другом порядке (исключая явную версию rbind):

A <- matrix(1:15, nrow=3)
n <- 600

benchmark(do.call("rbind", replicate(n, A, simplify=FALSE)),
          do.call("rbind", rep(list(A), n)),
          apply(A, 2, rep, n),
          matrix(rep(t(A),n), ncol=ncol(A), byrow=TRUE),
          order="relative", replications=10000)

дает

                                                 test replications elapsed
4  matrix(rep(t(A), n), ncol = ncol(A), byrow = TRUE)        10000    1.74
3                                 apply(A, 2, rep, n)        10000    2.57
2                   do.call("rbind", rep(list(A), n))        10000    2.79
1 do.call("rbind", replicate(n, A, simplify = FALSE))        10000    6.68
  relative user.self sys.self user.child sys.child
4    1.000      1.75        0         NA        NA
3    1.477      2.54        0         NA        NA
2    1.603      2.79        0         NA        NA
1    3.839      6.65        0         NA        NA

Если вы включаете явную версию rbind, она немного быстрее, чем версия do.call("rbind", rep(list(A), n)), но не намного и медленнее, чем версии apply или matrix. Таким образом, обобщение на произвольное n не требует потери скорости в этом случае.

Ответ 2

Вероятно, это более эффективно:

apply(A, 2, rep, n)

Ответ 3

Также так:

rep(1, n) %x% A

Ответ 4

как преобразовать его в массив, реплицировать содержимое и создать новую матрицу с обновленным количеством строк?

A <- matrix(...)
n = 2 # just a test

a = as.integer(A)
multi.a = rep(a,n)
multi.A = matrix(multi.a,nrow=nrow(A)*n,byrow=T)

Ответ 5

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

A[rep(seq(nrow(A)), n), ]