按行填充矩阵或转置按列填充的矩阵更快吗?
is it faster to fill a matrix by row or to transpose a matrix filled by columns?
我读到 R
在矩阵中使用列优先存储,这意味着附近列中的元素存储在连续块或类似的东西中。这让我想知道:
按行填充矩阵更快(在基本 R 函数 matrix()
中使用 byrow=TRUE
)还是先按列填充矩阵(使用默认 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
更快。
我认为这取决于列数和行数之间的关系。
需要注意的是,在"Filling a Matrix by Column and then Transpose it"的方法中,按行填充速度较快,但转置是速度的瓶颈。
- 行数 > 列数
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
和
> # fill by row
> system.time(x <- matrix(1, n, m, byrow=TRUE))
user system elapsed
1.18 0.18 1.47
> # fill by column
> system.time(y <- matrix(1, m, n))
user system elapsed
0.08 0.10 0.17
> # transpose
> system.time(t(y))
user system elapsed
2.47 0.14 2.63
在 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
我读到 R
在矩阵中使用列优先存储,这意味着附近列中的元素存储在连续块或类似的东西中。这让我想知道:
按行填充矩阵更快(在基本 R 函数 matrix()
中使用 byrow=TRUE
)还是先按列填充矩阵(使用默认 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
更快。
我认为这取决于列数和行数之间的关系。
需要注意的是,在"Filling a Matrix by Column and then Transpose it"的方法中,按行填充速度较快,但转置是速度的瓶颈。
- 行数 > 列数
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
和
> # fill by row
> system.time(x <- matrix(1, n, m, byrow=TRUE))
user system elapsed
1.18 0.18 1.47
> # fill by column
> system.time(y <- matrix(1, m, n))
user system elapsed
0.08 0.10 0.17
> # transpose
> system.time(t(y))
user system elapsed
2.47 0.14 2.63
在 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