最快的 R 相当于 MATLAB 的 reshape() 方法?
Fastest R equivalent to MATLAB's reshape() method?
我正在将一个 MATLAB 脚本转换成 R,到目前为止我很后悔,因为它现在比较慢。我正在尝试尽可能多地使用 "vectorized functions",但我对 R 比较陌生,不知道这是什么意思。根据我的研究,如果您使用大量运算符(包括括号),for 循环仅比 R 中的 apply() 方法慢。否则,我看不出 R 可以做些什么来进一步减慢它的速度。这是我想加快速度的有效代码。
somPEs <- 9;
inputPEs <- 6;
initial_w <- matrix(1, nrow=somPEs, ncol=inputPEs)
w <- apply(initial_w, 1, function(i) runif(i));
# Reshape w to a 3D matrix of dimension: c(sqrt(somPEs), sqrt(somPEs), inputPEs)
nw <- array(0, dim=c(sqrt(somPEs), sqrt(somPEs), inputPEs))
for (i in 1:inputPEs) {
nw[,,i] <- matrix(w[i,], nrow=sqrt(somPEs), ncol=sqrt(somPEs), byrow=TRUE)
}
w <- nw;
在 MATLAB 中,此代码由名为 "reshape" 的内置函数执行,如下所示:
w = reshape(w,[sqrt(somPEs) sqrt(somPEs) inputPEs]);
我为当前的 R 代码计时,它实际上非常快,但我仍然想了解矢量化以及如何将我的代码转换为 apply() 以提高可读性。
user system elapsed
0.003 0.000 0.002
第一步是将数组 w
从 6x9
大小转换为 3x3x6
大小,在您的情况下,这可以通过转置然后更改维度来完成:
neww <- t(w)
dim(neww) <- c(sqrt(somPEs), sqrt(somPEs), inputPEs)
这几乎就是我们想要的,除了前两个维度被翻转了。您可以使用 aperm
函数来转置它们:
neww <- aperm(neww, c(2, 1, 3))
这应该比遍历矩阵并逐行单独复制数据要快得多。为了看到这一点,让我们看一个更大的例子,它有 10,000 行和 100 列(它将映射到 10x10x10k 矩阵):
josilber <- function(w) {
neww <- t(w)
dim(neww) <- c(sqrt(dim(w)[2]), sqrt(dim(w)[2]), dim(w)[1])
aperm(neww, c(2, 1, 3))
}
OP <- function(w) {
nw <- array(0, dim=c(sqrt(dim(w)[2]), sqrt(dim(w)[2]), dim(w)[1]))
for (i in 1:(dim(w)[1])) {
nw[,,i] <- matrix(w[i,], nrow=sqrt(dim(w)[2]), ncol=sqrt(dim(w)[2]), byrow=TRUE)
}
nw
}
bigw <- matrix(runif(1000000), nrow=10000, ncol=100)
all.equal(josilber(bigw), OP(bigw))
# [1] TRUE
microbenchmark(josilber(bigw), OP(bigw))
# Unit: milliseconds
# expr min lq mean median uq max neval
# josilber(bigw) 8.483245 9.08430 14.46876 9.431534 11.76744 135.7204 100
# OP(bigw) 83.379053 97.07395 133.86606 117.223236 129.28317 1553.4381 100
使用 t
、dim
和 aperm
的方法比循环方法快 10 倍以上。
我没有测试速度,但你可以试试
nw1 <- aperm(`dim<-`(t(w), list(3, 3, 6)), c(2, 1, 3))
> nw1
, , 1
[,1] [,2] [,3]
[1,] 0.8257185 0.5475478 0.4157915
[2,] 0.8436991 0.3310513 0.1546463
[3,] 0.1794918 0.1836032 0.2675192
, , 2
[,1] [,2] [,3]
[1,] 0.6914582 0.1674163 0.2921129
[2,] 0.2558240 0.4269716 0.7335542
[3,] 0.6416367 0.8771934 0.6553210
, , 3
[,1] [,2] [,3]
[1,] 0.9761232 0.05223183 0.6651574
[2,] 0.5740032 0.80621864 0.2295017
[3,] 0.1138926 0.76009870 0.6932736
, , 4
[,1] [,2] [,3]
[1,] 0.437871558 0.5172516 0.1145181
[2,] 0.006923583 0.3235762 0.3751655
[3,] 0.823235642 0.4586850 0.6013853
, , 5
[,1] [,2] [,3]
[1,] 0.7425735 0.1665975 0.8659373
[2,] 0.1418979 0.1878132 0.2357267
[3,] 0.6963537 0.5391961 0.1112467
, , 6
[,1] [,2] [,3]
[1,] 0.7246276 0.02896792 0.04692648
[2,] 0.7563403 0.22027518 0.41138672
[3,] 0.8303413 0.31908307 0.25180560
我正在将一个 MATLAB 脚本转换成 R,到目前为止我很后悔,因为它现在比较慢。我正在尝试尽可能多地使用 "vectorized functions",但我对 R 比较陌生,不知道这是什么意思。根据我的研究,如果您使用大量运算符(包括括号),for 循环仅比 R 中的 apply() 方法慢。否则,我看不出 R 可以做些什么来进一步减慢它的速度。这是我想加快速度的有效代码。
somPEs <- 9;
inputPEs <- 6;
initial_w <- matrix(1, nrow=somPEs, ncol=inputPEs)
w <- apply(initial_w, 1, function(i) runif(i));
# Reshape w to a 3D matrix of dimension: c(sqrt(somPEs), sqrt(somPEs), inputPEs)
nw <- array(0, dim=c(sqrt(somPEs), sqrt(somPEs), inputPEs))
for (i in 1:inputPEs) {
nw[,,i] <- matrix(w[i,], nrow=sqrt(somPEs), ncol=sqrt(somPEs), byrow=TRUE)
}
w <- nw;
在 MATLAB 中,此代码由名为 "reshape" 的内置函数执行,如下所示:
w = reshape(w,[sqrt(somPEs) sqrt(somPEs) inputPEs]);
我为当前的 R 代码计时,它实际上非常快,但我仍然想了解矢量化以及如何将我的代码转换为 apply() 以提高可读性。
user system elapsed
0.003 0.000 0.002
第一步是将数组 w
从 6x9
大小转换为 3x3x6
大小,在您的情况下,这可以通过转置然后更改维度来完成:
neww <- t(w)
dim(neww) <- c(sqrt(somPEs), sqrt(somPEs), inputPEs)
这几乎就是我们想要的,除了前两个维度被翻转了。您可以使用 aperm
函数来转置它们:
neww <- aperm(neww, c(2, 1, 3))
这应该比遍历矩阵并逐行单独复制数据要快得多。为了看到这一点,让我们看一个更大的例子,它有 10,000 行和 100 列(它将映射到 10x10x10k 矩阵):
josilber <- function(w) {
neww <- t(w)
dim(neww) <- c(sqrt(dim(w)[2]), sqrt(dim(w)[2]), dim(w)[1])
aperm(neww, c(2, 1, 3))
}
OP <- function(w) {
nw <- array(0, dim=c(sqrt(dim(w)[2]), sqrt(dim(w)[2]), dim(w)[1]))
for (i in 1:(dim(w)[1])) {
nw[,,i] <- matrix(w[i,], nrow=sqrt(dim(w)[2]), ncol=sqrt(dim(w)[2]), byrow=TRUE)
}
nw
}
bigw <- matrix(runif(1000000), nrow=10000, ncol=100)
all.equal(josilber(bigw), OP(bigw))
# [1] TRUE
microbenchmark(josilber(bigw), OP(bigw))
# Unit: milliseconds
# expr min lq mean median uq max neval
# josilber(bigw) 8.483245 9.08430 14.46876 9.431534 11.76744 135.7204 100
# OP(bigw) 83.379053 97.07395 133.86606 117.223236 129.28317 1553.4381 100
使用 t
、dim
和 aperm
的方法比循环方法快 10 倍以上。
我没有测试速度,但你可以试试
nw1 <- aperm(`dim<-`(t(w), list(3, 3, 6)), c(2, 1, 3))
> nw1
, , 1
[,1] [,2] [,3]
[1,] 0.8257185 0.5475478 0.4157915
[2,] 0.8436991 0.3310513 0.1546463
[3,] 0.1794918 0.1836032 0.2675192
, , 2
[,1] [,2] [,3]
[1,] 0.6914582 0.1674163 0.2921129
[2,] 0.2558240 0.4269716 0.7335542
[3,] 0.6416367 0.8771934 0.6553210
, , 3
[,1] [,2] [,3]
[1,] 0.9761232 0.05223183 0.6651574
[2,] 0.5740032 0.80621864 0.2295017
[3,] 0.1138926 0.76009870 0.6932736
, , 4
[,1] [,2] [,3]
[1,] 0.437871558 0.5172516 0.1145181
[2,] 0.006923583 0.3235762 0.3751655
[3,] 0.823235642 0.4586850 0.6013853
, , 5
[,1] [,2] [,3]
[1,] 0.7425735 0.1665975 0.8659373
[2,] 0.1418979 0.1878132 0.2357267
[3,] 0.6963537 0.5391961 0.1112467
, , 6
[,1] [,2] [,3]
[1,] 0.7246276 0.02896792 0.04692648
[2,] 0.7563403 0.22027518 0.41138672
[3,] 0.8303413 0.31908307 0.25180560