R 有没有办法说 "do n times" 而不必编写带有冗余变量的 for 循环?
Does R have a way to say "do n times" without having to write a for loop with a redundant variable?
I recently wrote 这行代码:for(i in seq_len(exponent)){out<-squareMat%*%out}
。显然,从未使用过 i
,我只想说“exponent
次,做 out<-squareMat%*%out
”。没有冗余计数器 i
有没有办法做到这一点?例如,是否有 apply
家庭功能?
示例 - 我有:
squareMat<-matrix(c(0,10,20,30),2,2)
out<-diag(nrow = nrow(squareMat))
exponent<-5
for(i in seq_len(exponent)){out<-squareMat%*%out}
out
我想要的是:
squareMat<-matrix(c(0,10,20,30),2,2)
out<-diag(nrow = nrow(squareMat))
exponent<-5
[do exponent times]{out<-squareMat%*%out}
out
这是一个使用 sapply
的例子。
myfunc <- function(s) {
return('hello')
}
sapply(seq_len(5), myfunc)
# [1] "hello" "hello" "hello" "hello" "hello"
是的,确实如此。 base R
中有几个有用的函数,这些函数现在不常使用。其中之一完全符合您的要求。 replicate
函数将表达式 (expr
) 复制 n
次。它的工作原理如下,假设我想从均匀(0 到 1)分布生成 3 个大小为 5 的不同样本。使用 replicate
可以轻松完成。看看下面的这段代码
replicate(n = 3, expr = {runif(n = 5)})
# [,1] [,2] [,3]
# [1,] 0.1944426 0.5158065 0.39892501
# [2,] 0.5676580 0.9940599 0.97385575
# [3,] 0.5570141 0.2274214 0.60239883
# [4,] 0.5074303 0.3526040 0.95445298
# [5,] 0.1931812 0.4593620 0.03283596
结果自动组织成 array
(在本例中为矩阵)。但是,您可以设置参数simplify = FALSE
。然后,return 将是一个列表
replicate(n = 3, expr = {runif(n = 5)}, simplify = FALSE)
# [[1]]
# [1] 0.4694347 0.9559887 0.8110113 0.7528089 0.6639614
#
# [[2]]
# [1] 0.8731027 0.7295846 0.3773571 0.5394776 0.6792322
#
# [[3]]
# [1] 0.3463870 0.3776352 0.3895620 0.2166284 0.5065204
重要的是要注意这些复制中的每一个都是相互独立的。如果你想按顺序复制某些东西,你必须使用 for
循环或其他合适的函数。例如,存在一个名为 rapply
的函数(递归 lapply)。但是,我一直不清楚使用它的最佳方式。
对于像 %*%
这样的二元运算,您可以使用 Reduce
,可选地使用 init
参数(实际上这里不需要,因为 init
是单位矩阵,请参阅@尼古拉的评论,但使回答更笼统):
squareMat<-matrix(c(0,10,20,30),2,2)
exponent<-5
Reduce('%*%', init = diag(nrow = nrow(squareMat)), replicate(exponent, squareMat, simplify=F))
#> [,1] [,2]
#> [1,] 7800000 27800000
#> [2,] 13900000 49500000
这可以通过在计算中不使用第二个参数来加速避免调用 replicate
(1:exponent
仅充当计数器):
Reduce(function(x,notused) {squareMat %*% x}, init = diag(nrow = nrow(squareMat)), 1:exponent)
#> [,1] [,2]
#> [1,] 7800000 27800000
#> [2,] 13900000 49500000
请注意,在这种情况下,Reduce
的效率低于简单循环,因此,有趣但可能不是最优的:
microbenchmark::microbenchmark(test_reduce(),test_reduce2(),test_loop())
Unit: microseconds
expr min lq mean median uq max neval cld
test_reduce() 17.2 17.7 21.461 18.0 18.60 97.4 100 c
test_reduce2() 7.9 8.4 9.463 8.6 8.85 25.9 100 b
test_loop() 3.0 3.2 3.786 3.3 3.40 26.2 100 a
另一种方法是在函数调用中使用 Recall()
。
my_mat_power = function(n) {
if (n == 1)
squareMat
else
Recall(n - 1) %*% squareMat
}
my_mat_power(5)
## [,1] [,2]
## [1,] 7800000 27800000
## [2,] 13900000 49500000
如果你想让你的矩阵成为一个变量,你可以做一些小的修改:
my_mat_power = function(n, mat) {
if (n == 1)
mat
else
Recall(n - 1, mat) %*% mat
}
让我们看看这个:
library(expm)
squareMat %^% 5
R 几乎总有办法避免循环。你的情况:
library(expm)
out <- (squareMat%^%exponent)%*%out
I recently wrote 这行代码:for(i in seq_len(exponent)){out<-squareMat%*%out}
。显然,从未使用过 i
,我只想说“exponent
次,做 out<-squareMat%*%out
”。没有冗余计数器 i
有没有办法做到这一点?例如,是否有 apply
家庭功能?
示例 - 我有:
squareMat<-matrix(c(0,10,20,30),2,2)
out<-diag(nrow = nrow(squareMat))
exponent<-5
for(i in seq_len(exponent)){out<-squareMat%*%out}
out
我想要的是:
squareMat<-matrix(c(0,10,20,30),2,2)
out<-diag(nrow = nrow(squareMat))
exponent<-5
[do exponent times]{out<-squareMat%*%out}
out
这是一个使用 sapply
的例子。
myfunc <- function(s) {
return('hello')
}
sapply(seq_len(5), myfunc)
# [1] "hello" "hello" "hello" "hello" "hello"
是的,确实如此。 base R
中有几个有用的函数,这些函数现在不常使用。其中之一完全符合您的要求。 replicate
函数将表达式 (expr
) 复制 n
次。它的工作原理如下,假设我想从均匀(0 到 1)分布生成 3 个大小为 5 的不同样本。使用 replicate
可以轻松完成。看看下面的这段代码
replicate(n = 3, expr = {runif(n = 5)})
# [,1] [,2] [,3]
# [1,] 0.1944426 0.5158065 0.39892501
# [2,] 0.5676580 0.9940599 0.97385575
# [3,] 0.5570141 0.2274214 0.60239883
# [4,] 0.5074303 0.3526040 0.95445298
# [5,] 0.1931812 0.4593620 0.03283596
结果自动组织成 array
(在本例中为矩阵)。但是,您可以设置参数simplify = FALSE
。然后,return 将是一个列表
replicate(n = 3, expr = {runif(n = 5)}, simplify = FALSE)
# [[1]]
# [1] 0.4694347 0.9559887 0.8110113 0.7528089 0.6639614
#
# [[2]]
# [1] 0.8731027 0.7295846 0.3773571 0.5394776 0.6792322
#
# [[3]]
# [1] 0.3463870 0.3776352 0.3895620 0.2166284 0.5065204
重要的是要注意这些复制中的每一个都是相互独立的。如果你想按顺序复制某些东西,你必须使用 for
循环或其他合适的函数。例如,存在一个名为 rapply
的函数(递归 lapply)。但是,我一直不清楚使用它的最佳方式。
对于像 %*%
这样的二元运算,您可以使用 Reduce
,可选地使用 init
参数(实际上这里不需要,因为 init
是单位矩阵,请参阅@尼古拉的评论,但使回答更笼统):
squareMat<-matrix(c(0,10,20,30),2,2)
exponent<-5
Reduce('%*%', init = diag(nrow = nrow(squareMat)), replicate(exponent, squareMat, simplify=F))
#> [,1] [,2]
#> [1,] 7800000 27800000
#> [2,] 13900000 49500000
这可以通过在计算中不使用第二个参数来加速避免调用 replicate
(1:exponent
仅充当计数器):
Reduce(function(x,notused) {squareMat %*% x}, init = diag(nrow = nrow(squareMat)), 1:exponent)
#> [,1] [,2]
#> [1,] 7800000 27800000
#> [2,] 13900000 49500000
请注意,在这种情况下,Reduce
的效率低于简单循环,因此,有趣但可能不是最优的:
microbenchmark::microbenchmark(test_reduce(),test_reduce2(),test_loop())
Unit: microseconds
expr min lq mean median uq max neval cld
test_reduce() 17.2 17.7 21.461 18.0 18.60 97.4 100 c
test_reduce2() 7.9 8.4 9.463 8.6 8.85 25.9 100 b
test_loop() 3.0 3.2 3.786 3.3 3.40 26.2 100 a
另一种方法是在函数调用中使用 Recall()
。
my_mat_power = function(n) {
if (n == 1)
squareMat
else
Recall(n - 1) %*% squareMat
}
my_mat_power(5)
## [,1] [,2]
## [1,] 7800000 27800000
## [2,] 13900000 49500000
如果你想让你的矩阵成为一个变量,你可以做一些小的修改:
my_mat_power = function(n, mat) {
if (n == 1)
mat
else
Recall(n - 1, mat) %*% mat
}
让我们看看这个:
library(expm)
squareMat %^% 5
R 几乎总有办法避免循环。你的情况:
library(expm)
out <- (squareMat%^%exponent)%*%out