R 为什么使用apply时矩阵的元素乘积要快得多?
我想把矩阵的所有元素相乘。我可以用两个for循环或apply来完成。我的直觉是for循环会更快。Apply必须创建一个临时向量来存储行乘积的结果,然后将乘积应用于该行 它仍然必须执行for循环以将所有元素相乘,因此这只是存储中间结果的额外操作,而for循环方法不必这样做。但速度仍然是原来的4倍。为什么呢R 为什么使用apply时矩阵的元素乘积要快得多?,r,performance,R,Performance,我想把矩阵的所有元素相乘。我可以用两个for循环或apply来完成。我的直觉是for循环会更快。Apply必须创建一个临时向量来存储行乘积的结果,然后将乘积应用于该行 它仍然必须执行for循环以将所有元素相乘,因此这只是存储中间结果的额外操作,而for循环方法不必这样做。但速度仍然是原来的4倍。为什么呢 cols <- 1000 rows <- 1000 a <- matrix(runif(cols * rows, 1, 2), nrow = rows) system.ti
cols <- 1000
rows <- 1000
a <- matrix(runif(cols * rows, 1, 2), nrow = rows)
system.time({
result <- 1
for(i in 1:nrow(a)) {
for(j in 1:ncol(a)) {
result <- result * a[i, j]
}
}
})
# 0.09s
system.time(result <- prod(apply(a, 1, prod)))
# 0.01s
应用速度似乎更快,因为仍有一些矢量化正在进行。循环考虑:
对我来说,应用的速度和应用的速度差不多。看起来应用的速度更快,因为还有一些矢量化在进行。循环考虑:
对我来说,这与应用的速度一样快。要进行矢量化而不是应用,可以使用matrixStats中的RowProd:
矢量化而不是应用大约需要18毫秒。您可以使用matrixStats中的RowProd:
大约需要18毫秒以下是我在测试各种方法时得到的结果。我对Inf是许多计算的结果这一事实有些担心,我想知道对0-1范围的限制是否会有所不同。像@badmax一样,我对proda的速度相对较慢感到惊讶。在我看来,它应该用C编码,而且效率更高。我还推断,面向列的方法可能比面向行的方法更快,因为这就是R中矩阵的存储方式,并且是正确的:
library(microbenchmark)
cols <- 1000
rows <- 1000
a <- matrix(runif(cols * rows, 1, 2), nrow = rows)
microbenchmark(loop1 ={
result <- 1
for(i in 1:nrow(a)) {
for(j in 1:ncol(a)) {
result <- result * a[i, j]
} } },
loop2 ={result <- 1
for(j in 1:ncol(a)) {
result <- result * prod(a[ , j])
} },
loop3 = {
result <- 1
for(i in 1:nrow(a)) {
result <- result * prod( a[i, ])
} },
apply_test = {result <- prod(apply(a, 1, prod))},
prod_test = {result <- prod(a) },
Reduce_test = {result <- Reduce("*", a)},
log_sum = { result<- exp( sum(log(a)))}) #since sum of logs == log of prod
#====================
Unit: milliseconds
expr min lq mean median uq max neval cld
loop1 58.872740 59.782277 60.665321 60.246169 61.156176 67.33558 100 c
loop2 5.314437 5.843748 7.316167 6.024948 6.626402 57.36532 100 a
loop3 9.614727 10.248335 11.521343 10.541872 10.947829 45.08280 100 ab
apply_test 8.336721 8.924148 9.960122 9.166424 9.429118 17.35621 100 ab
prod_test 94.314333 95.438939 95.956394 95.911858 96.286444 98.54229 100 d
Reduce_test 292.907175 312.754959 389.959756 354.369616 511.151578 545.80829 100 e
log_sum 19.258281 19.916965 22.333617 20.134510 20.551704 180.18492 100 b
prod函数现在从相对于循环和应用方法的较低位置被解救出来。以下是我通过对各种方法进行基准测试而得到的结果。我对Inf是许多计算的结果这一事实有些担心,我想知道对0-1范围的限制是否会有所不同。像@badmax一样,我对proda的速度相对较慢感到惊讶。在我看来,它应该用C编码,而且效率更高。我还推断,面向列的方法可能比面向行的方法更快,因为这就是R中矩阵的存储方式,并且是正确的:
library(microbenchmark)
cols <- 1000
rows <- 1000
a <- matrix(runif(cols * rows, 1, 2), nrow = rows)
microbenchmark(loop1 ={
result <- 1
for(i in 1:nrow(a)) {
for(j in 1:ncol(a)) {
result <- result * a[i, j]
} } },
loop2 ={result <- 1
for(j in 1:ncol(a)) {
result <- result * prod(a[ , j])
} },
loop3 = {
result <- 1
for(i in 1:nrow(a)) {
result <- result * prod( a[i, ])
} },
apply_test = {result <- prod(apply(a, 1, prod))},
prod_test = {result <- prod(a) },
Reduce_test = {result <- Reduce("*", a)},
log_sum = { result<- exp( sum(log(a)))}) #since sum of logs == log of prod
#====================
Unit: milliseconds
expr min lq mean median uq max neval cld
loop1 58.872740 59.782277 60.665321 60.246169 61.156176 67.33558 100 c
loop2 5.314437 5.843748 7.316167 6.024948 6.626402 57.36532 100 a
loop3 9.614727 10.248335 11.521343 10.541872 10.947829 45.08280 100 ab
apply_test 8.336721 8.924148 9.960122 9.166424 9.429118 17.35621 100 ab
prod_test 94.314333 95.438939 95.956394 95.911858 96.286444 98.54229 100 d
Reduce_test 292.907175 312.754959 389.959756 354.369616 511.151578 545.80829 100 e
log_sum 19.258281 19.916965 22.333617 20.134510 20.551704 180.18492 100 b
prod函数现在从相对于循环和应用方法的较低位置被解救出来。为什么不执行proda?这需要0.13秒,比它们都慢。是的,我在测试时更改了runif的范围。但这确实让我怀疑结果是否与此有关?产品趋向于非常快地变为0或Inf。为什么不做proda?这需要0.13秒,比所有产品都慢。是的,我在测试时更改了runif的范围。但这确实让我怀疑结果是否与此有关?产品倾向于很快变为0或Inf。因此,当产品未达到Inf时,是否可以安全地得出结论,prod是最好的?这是我最初的预期,似乎得到了这一证据的支持。安全我不会直截了当的。这毕竟是统计数据。那么,当产品未达到Inf时,是否可以安全地得出结论,即prod是最好的?这是我最初的预期,似乎得到了这一证据的支持。安全我不会直截了当的。这毕竟是统计数字。
library(microbenchmark)
cols <- 1000
rows <- 1000
a <- matrix(runif(cols * rows, 1, 2), nrow = rows)
microbenchmark(loop1 ={
result <- 1
for(i in 1:nrow(a)) {
for(j in 1:ncol(a)) {
result <- result * a[i, j]
} } },
loop2 ={result <- 1
for(j in 1:ncol(a)) {
result <- result * prod(a[ , j])
} },
loop3 = {
result <- 1
for(i in 1:nrow(a)) {
result <- result * prod( a[i, ])
} },
apply_test = {result <- prod(apply(a, 1, prod))},
prod_test = {result <- prod(a) },
Reduce_test = {result <- Reduce("*", a)},
log_sum = { result<- exp( sum(log(a)))}) #since sum of logs == log of prod
#====================
Unit: milliseconds
expr min lq mean median uq max neval cld
loop1 58.872740 59.782277 60.665321 60.246169 61.156176 67.33558 100 c
loop2 5.314437 5.843748 7.316167 6.024948 6.626402 57.36532 100 a
loop3 9.614727 10.248335 11.521343 10.541872 10.947829 45.08280 100 ab
apply_test 8.336721 8.924148 9.960122 9.166424 9.429118 17.35621 100 ab
prod_test 94.314333 95.438939 95.956394 95.911858 96.286444 98.54229 100 d
Reduce_test 292.907175 312.754959 389.959756 354.369616 511.151578 545.80829 100 e
log_sum 19.258281 19.916965 22.333617 20.134510 20.551704 180.18492 100 b
Unit: milliseconds
expr min lq mean median uq max neval cld
loop1 56.693831 58.846847 59.688896 59.448108 60.208619 63.005431 100 c
loop2 5.667955 5.907125 10.090634 6.109151 6.532552 183.985617 100 ab
loop3 9.533779 10.080330 12.760057 10.431867 10.734991 183.262217 100 ab
apply_test 8.144015 8.622861 9.940263 8.904425 9.962390 17.470028 100 ab
prod_test 1.327710 1.371449 1.411990 1.394160 1.432646 1.677596 100 a
Reduce_test 293.697339 312.384739 385.437743 356.997439 500.446356 557.253762 100 d
log_sum 22.444015 23.224879 24.064932 23.539085 24.210656 29.774315 100 b