16

我有一个矩阵并寻找一种有效的方法来复制它 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% 用于执行 rbind。)

有谁知道更好的解决方案?

4

6 回答 6

25

还有两个解决方案:

首先是对问题中示例的修改

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

所以最快的是原始rbind调用,但假设n是固定的并且提前知道。如果n不固定,那么最快的是do.call("rbind", rep(list(A), n). 这些是针对 3x5 矩阵和 10 次复制的。不同大小的矩阵可能会给出不同的排序。

编辑:

对于 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))版本稍快,但不会快很多,并且比applyormatrix版本慢。因此,在这种情况下,对任意的泛化n不需要损失速度。

于 2012-10-23T16:53:40.923 回答
10

可能这更有效:

apply(A, 2, rep, n)
于 2012-10-23T16:19:07.417 回答
3

还有这种方式:

rep(1, n) %x% A
于 2015-08-01T22:37:18.403 回答
1

您可以使用索引

A[rep(seq(nrow(A)), n), ]
于 2015-08-01T22:48:31.067 回答
1

我出于与原始海报相同的原因来到这里,并最终更新了@Brian Diggs 比较以包括所有其他发布的答案。希望我正确地做到了这一点:

#install.packages("rbenchmark")
library("rbenchmark")
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),
          A[rep(seq(nrow(A)), n), ],
          rep(1, n) %x% A,
          apply(A, 2, rep, n),
          matrix(rep(as.integer(t(A)),n),nrow=nrow(A)*n,byrow=TRUE),
     order="relative", replications=10000)

#                                                                test replications elapsed relative user.self sys.self user.child sys.child
#5                                          A[rep(seq(nrow(A)), n), ]        10000    0.32    1.000      0.33     0.00         NA        NA
#8 matrix(rep(as.integer(t(A)), n), nrow = nrow(A) * n, byrow = TRUE)        10000    0.36    1.125      0.35     0.02         NA        NA
#4                 matrix(rep(t(A), n), ncol = ncol(A), byrow = TRUE)        10000    0.38    1.188      0.37     0.00         NA        NA
#3                                                apply(A, 2, rep, n)        10000    0.59    1.844      0.56     0.03         NA        NA
#7                                                apply(A, 2, rep, n)        10000    0.61    1.906      0.58     0.03         NA        NA
#6                                                    rep(1, n) %x% A        10000    1.44    4.500      1.42     0.02         NA        NA
#2                                  do.call("rbind", rep(list(A), n))        10000    1.67    5.219      1.67     0.00         NA        NA
#1                do.call("rbind", replicate(n, A, simplify = FALSE))        10000    5.03   15.719      5.02     0.01         NA        NA
于 2021-04-04T21:49:15.283 回答
0

将其转换为数组,复制内容并使用更新的行数创建一个新矩阵怎么样?

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)
于 2012-10-23T16:23:32.690 回答