按行填充矩阵或转置由列填充的矩阵更快吗?

时间:2019-12-30 21:06:33

标签: r performance matrix benchmarking microbenchmark

我读到R在矩阵中使用列优先存储,这意味着附近列中的元素存储在连续的块或类似的块中。这让我感到奇怪: 是按行填充矩阵更快(使用基本R函数byrow=TRUE中的matrix()),还是先按列填充矩阵(使用默认的byrow=FALSE然后更快)用t()转置它吗?


我尝试进行基准测试。

按行填充矩阵

> microbenchmark(matrix(1, n, n, byrow=TRUE))
Unit: seconds
                          expr      min       lq     mean   median       uq      max neval
 matrix(1, n, n, byrow = TRUE) 1.047379 1.071353 1.105468 1.081795 1.112995 1.628675   100

按列填充矩阵,然后转置

> microbenchmark(t(matrix(1, n, n)))
Unit: seconds
               expr     min       lq     mean  median       uq      max neval
 t(matrix(1, n, n)) 1.43931 1.536333 1.692572 1.61793 1.726244 3.070821   100

结论

似乎逐行填充矩阵更快!我想念什么吗?我本以为R会用t()做一些重新标记,但实际上比逐行填写矩阵要慢!

对此有解释吗?我很困惑。

观察

在ThomasIsCoding的回答和对自己进行基准测试几次之后,它似乎取决于行数和列数。

  • 行数<列数:t()更快。
  • 行数=列数:byrow=TRUE更快。
  • 行数>列数:byrow=TRUE更快。

2 个答案:

答案 0 :(得分:5)

我认为这取决于列数和行数之间的关系。

应该注意,在“按列填充矩阵然后转置”方法中,按行填充速度更快,但是转置是速度的瓶颈。

  • 行数>列数
filelist.txt

如此

n <- 1e5
m <- 1e3
microbenchmark(matrix(1, n, m, byrow=TRUE),
               t(matrix(1, m, n)),
               check = "equal",
               unit = "relative",
               times = 10)

Unit: relative
                          expr     min       lq     mean   median       uq      max neval
 matrix(1, n, m, byrow = TRUE) 1.00000 1.000000 1.000000 1.000000 1.000000 1.000000    10
            t(matrix(1, m, n)) 3.57835 3.556422 3.935004 3.583247 3.714243 4.820607    10
  • 行数<列数
> # fill by row
> system.time(x <- matrix(1, n, m, byrow=TRUE))
   user  system elapsed 
   0.48    0.08    0.61 
> # fill by column
> system.time(y <- matrix(1, m, n))
   user  system elapsed 
   0.03    0.14    0.17 
> # transpose
> system.time(t(y))
   user  system elapsed 
   1.59    0.08    1.71 

如此

n <- 1e3
m <- 1e5
microbenchmark(matrix(1, n, m, byrow=TRUE),
               t(matrix(1, m, n)),
               check = "equal",
               unit = "relative",
               times = 10)

Unit: relative
                          expr      min       lq     mean   median       uq      max neval
 matrix(1, n, m, byrow = TRUE) 1.885902 1.893168 1.717817 1.730453 1.744869 1.480463    10
            t(matrix(1, m, n)) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10
  • 行数=列数
> # fill by row
> system.time(x <- matrix(1, n, m, byrow=TRUE))
   user  system elapsed 
   0.92    0.39    1.33 

> # fill by column
> system.time(y <- matrix(1, m, n))
   user  system elapsed 
   0.13    0.08    0.20 

> # transpose
> system.time(t(y))
   user  system elapsed 
   0.47    0.10    0.58 

如此

n <- 1e4
m <- 1e4
microbenchmark(matrix(1, n, m, byrow=TRUE),
               t(matrix(1, m, n)),
               check = "equal",
               unit = "relative",
               times = 10)

Unit: relative
                          expr      min       lq     mean   median       uq      max neval
 matrix(1, n, m, byrow = TRUE) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10
            t(matrix(1, m, n)) 1.163218 1.197249 1.279579 1.178185 1.354539 1.387548    10

答案 1 :(得分:4)

在R中,矩阵按列存储为向量。按列填充矩阵比按行填充矩阵更有效。转置函数复制带有重新排列元素的基础向量。结果,按列填充和进行转置的总时间是两种相反效果的组合:更有效地填充矩阵,并增加了复制和重新排列的开销。

添加类似于ThomasIsCoding的基准来解决这些评论:

library(microbenchmark)

n <- 1e5
m <- 1e3
microbenchmark(matrix(1, n, m, byrow=TRUE),
               matrix(1, n, m),
               t(matrix(1, m, n)),
               check = "equal",
               unit = "relative",
               times = 10)
## Unit: relative
##                           expr      min       lq     mean   median       uq      max neval cld
##  matrix(1, n, m, byrow = TRUE) 1.842346 1.881930 1.628921 1.735783 1.294805 1.569826    10  b 
##                matrix(1, n, m) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10 a  
##             t(matrix(1, m, n)) 6.205065 6.459522 5.371109 5.944001 4.492510 4.449736    10   c

n <- 1e3
m <- 1e5
microbenchmark(matrix(1, n, m, byrow=TRUE),
               matrix(1, n, m),
               t(matrix(1, m, n)),
               check = "equal",
               unit = "relative",
               times = 10)
## Unit: relative
##                           expr      min       lq     mean   median       uq      max neval cld
##  matrix(1, n, m, byrow = TRUE) 4.058060 4.002568 3.249719 3.203163 2.769305 2.719077    10   c
##                matrix(1, n, m) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10 a  
##             t(matrix(1, m, n)) 2.956505 2.973743 2.508964 2.471689 2.218416 2.162319    10  b 

n <- 1e4
m <- 1e4
microbenchmark(matrix(1, n, m, byrow=TRUE),
               matrix(1, n, m),
               t(matrix(1, m, n)),
               check = "equal",
               unit = "relative",
               times = 10)
## Unit: relative
##                           expr      min       lq     mean   median       uq      max neval cld
##  matrix(1, n, m, byrow = TRUE) 4.378733 4.273794 3.721100 4.240410 2.902938 3.180665    10  b 
##                matrix(1, n, m) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10 a  
##             t(matrix(1, m, n)) 5.659562 5.797812 5.062428 5.894572 4.195282 3.876377    10   c