最快的 R 相当于 MATLAB 的 reshape() 方法?

问题描述 投票:0回答:3

我正在将 MATLAB 脚本转换为 R,但到目前为止我很后悔,因为它目前速度较慢。我尝试尽可能多地使用“向量化函数”,但我对 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 
r performance matlab vectorization reshape
3个回答
5
投票

第一步是将数组

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 倍以上。


2
投票

我没有测试速度,但你可以尝试一下

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

0
投票

为什么不直接使用

array()
来重塑。请参阅以下代码:

somPEs   <- 9
inputPEs <- 6
w <- matrix(rnorm(somPEs*inputPEs), nrow=somPEs, ncol=inputPEs)
w
#>               [,1]         [,2]       [,3]       [,4]       [,5]        [,6]
#>  [1,]  0.781139046  0.009672953 -0.5457179  1.7150008 -0.9694289  0.20372149
#>  [2,] -1.143725888 -1.188597323 -0.6131516  0.1240463  1.6653479  0.92304619
#>  [3,]  0.005797624 -0.795521816 -0.3360094  0.3578852  0.9193485  0.14380867
#>  [4,] -0.747908833 -0.456375025 -0.3896752  0.5539691 -1.1029344 -0.70929883
#>  [5,] -0.789205038 -1.418077386  1.4721101  0.6127520 -0.4742705  0.08470037
#>  [6,] -0.057106439 -0.112531322 -0.3436132  0.3480150 -0.3856746 -0.63150498
#>  [7,] -0.135470040 -2.282978444  0.3586637 -0.0773639 -0.7468404  0.13561098
#>  [8,] -0.156641966  0.339490305  2.0096249  0.1248149 -0.4547921 -0.07860635
#>  [9,]  0.065463091 -0.075989164 -2.6767654 -0.2690637 -0.7618482 -1.08372401
nw <- array(w, c(sqrt(somPEs), sqrt(somPEs), inputPEs))
nw
#> , , 1
#> 
#>              [,1]        [,2]        [,3]
#> [1,]  0.781139046 -0.74790883 -0.13547004
#> [2,] -1.143725888 -0.78920504 -0.15664197
#> [3,]  0.005797624 -0.05710644  0.06546309
#> 
#> , , 2
#> 
#>              [,1]       [,2]        [,3]
#> [1,]  0.009672953 -0.4563750 -2.28297844
#> [2,] -1.188597323 -1.4180774  0.33949030
#> [3,] -0.795521816 -0.1125313 -0.07598916
#> 
#> , , 3
#> 
#>            [,1]       [,2]       [,3]
#> [1,] -0.5457179 -0.3896752  0.3586637
#> [2,] -0.6131516  1.4721101  2.0096249
#> [3,] -0.3360094 -0.3436132 -2.6767654
#> 
#> , , 4
#> 
#>           [,1]      [,2]       [,3]
#> [1,] 1.7150008 0.5539691 -0.0773639
#> [2,] 0.1240463 0.6127520  0.1248149
#> [3,] 0.3578852 0.3480150 -0.2690637
#> 
#> , , 5
#> 
#>            [,1]       [,2]       [,3]
#> [1,] -0.9694289 -1.1029344 -0.7468404
#> [2,]  1.6653479 -0.4742705 -0.4547921
#> [3,]  0.9193485 -0.3856746 -0.7618482
#> 
#> , , 6
#> 
#>           [,1]        [,2]        [,3]
#> [1,] 0.2037215 -0.70929883  0.13561098
#> [2,] 0.9230462  0.08470037 -0.07860635
#> [3,] 0.1438087 -0.63150498 -1.08372401

创建于 2024-09-20,使用 reprex v2.1.0

© www.soinside.com 2019 - 2024. All rights reserved.