提问人:stats_noob 提问时间:11/24/2021 更新时间:11/25/2021 访问量:2409
R:满足条件时停止循环
R: Stopping a Loop When a Condition is Met
问:
我正在使用 R 编程语言。我创建了以下循环,生成 1000 个随机数 - 然后重复此过程 10 次:
results <- list()
for (i in 1:10){
a = rnorm(1000,10,1)
b = rnorm(1000,10,1)
d_i = data.frame(a,b)
d_i$index = 1:nrow(d_i)
d_i$iteration = as.factor(i)
results[[i]] <- d_i
}
results_df <- do.call(rbind.data.frame, results)
问题:我想改变这个循环,这样它就不会只生成 1000 个随机数,而是不断生成随机数,直到满足某个条件,例如:KEEP 生成随机数,直到 d_i$a > 10 和 d_i$b > 10。
使用“WHILE()”语句,我尝试这样做:
results <- list()
for (i in 1:10){
while (d_i$a > 10 & d_i$b >10) {
a = rnorm(1000,10,1)
b = rnorm(1000,10,1)
d_i = data.frame(a,b)
d_i$index = 1:nrow(d_i)
d_i$iteration = as.factor(i)
results[[i]] <- d_i
}
}
results_df <- do.call(rbind.data.frame, results)
问题:但是,这将返回以下警告(10 次):
Warning messages:
1: In while (d_i$a > 10 & d_i$b > 10) { :
the condition has length > 1 and only the first element will be used
并生成一个空表:
> results_df
data frame with 0 columns and 0 rows
有人可以帮我解决这个问题吗?
谢谢!
答:
要打破循环(while 或 for),只需在条件之后。break()
if
out <- vector("integer", 26)
for (i in seq_along(letters)) {
if(letters[i] == "t") break()
out[i] <- i+1
}
out
#> [1] 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 0 0 0 0 0 0 0
将打破循环。From : 控制权被转移到最内层循环之外的第一个语句。?break
但是,从您的问题来看,您为什么不完全清楚为什么要这样做 - 这种控制流可能不是合适的解决方案,因为可能存在矢量化解决方案。此外,要注意不要在循环中做一些不必要的事情——这是代码运行缓慢的常见原因。在这里,我们可以从 for 循环中取出一些东西,例如 和 ,但最终仍然会得到相同的结果。看看第三圈。d_i$iteration
d_i$index
我希望这些评论有助于了解它的工作原理。它主要利用它只是一个无限循环。可以使用关键字停止它。repeat
break
results <- list()
for (i in 1:10){
# do until break
repeat {
# repeat many random numbers
a = rnorm(1000,10,1)
b = rnorm(1000,10,1)
# does any pair meet the requirement
if (any(a > 10 & b > 10)) {
# put it in a data.frame
d_i = data.frame(a,b)
# end repeat
break
}
}
# select all rows until the first time the requirement is met
# it must be met, otherwise the loop would not have ended
d_i <- d_i[1:which(d_i$a > 10 & d_i$b > 10)[1], ]
# prep other variables
d_i$index = seq_len(nrow(d_i))
d_i$iteration = as.factor(i)
results[[i]] <- d_i
}
原始帖子中的错误消息是由于 和 是具有 1,000 个元素的向量,而 10 是标量。因此,R 将 in 中的第一个元素和 in 中的第一个元素与 10 进行比较。d_i$a
d_i$b
d_i$a
d_i$b
为了解决错误消息,我们需要将长度为 1 的向量与标量 10 进行比较。这需要重构代码以一次生成一个随机数。从原始帖子中的描述来看,尚不清楚这种行为是否是故意的。
我将通过消除 10 个复制的集合来简化问题,以说明如何创建具有随机数的数据框,直到一行同时具有两者且值大于 10。a
b
首先,我们设置一个种子以使答案可重现,然后初始化一些对象。通过设置 和 to 0,我们确保循环至少执行一次。a
b
while()
set.seed(950141238) # for reproducibility
results <- list()
a <- 0 # initialize a to a number < 10
b <- 0 # initialize b to a number < 10
i <- 1 # set a counter
初始化 和 后,循环的计算结果为生成两个随机数,分配一个索引值,并将它们作为数据框写入列表。循环的逻辑指示,如果小于或等于 10 或小于或等于 10,则循环将继续迭代。当两者都大于 10 时,它停止。a
b
while()
TRUE
results
while()
a
b
a
b
while(a <= 10 | b <= 10){
a <- rnorm(1,10,1) # generate 1 random number with mean of 10 and sd of 1
b <- rnorm(1,10,1) # ditto
results[[i]] <- data.frame(index = i,a,b)
i <- i + 1 # increment i
}
循环在第九次迭代后停止执行,正如我们在将各个行与 和 组合后打印生成的数据帧所看到的那样。do.call()
rbind()
df <- do.call(rbind,results)
df
...和输出:
> df
index a b
1 1 8.682442 8.846653
2 2 9.204682 8.501692
3 3 8.886819 10.488972
4 4 11.264142 8.952981
5 5 9.900112 10.918042
6 6 9.185120 10.625667
7 7 9.620793 10.316724
8 8 11.718397 9.256835
9 9 10.034793 11.634023
>
请注意,数据框中最后一行的值都大于 10 和 。a
b
while 循环的多个复制
为了像原始帖子中那样重复该过程 10 次,我们将操作包装在一个循环中,并添加第二个列表,以保存每次迭代的结果。for()
combined_results
set.seed(950141238) # for reproducibility
combined_results <- list()
for(iteration in 1:10){
results <- list()
a <- 0 # initialize a to a number < 10
b <- 0 # initialize b to a number < 10
i <- 1 # set a counter
while((a < 10) | (b < 10)){
a <- rnorm(1,10,1) # generate 1 random number with mean of 10 and sd of 1
b <- rnorm(1,10,1) # ditto
results[[i]] <- data.frame(iteration,index = i,a,b)
i <- i + 1 # increment i
}
combined_results[[iteration]] <- do.call(rbind,results)
}
df <- do.call(rbind,combined_results)
df[df$iteration < 5,]
...以及外部循环前 4 次迭代的输出:
> df[df$iteration < 5,]
iteration index a b
1 1 1 8.682442 8.846653
2 1 2 9.204682 8.501692
3 1 3 8.886819 10.488972
4 1 4 11.264142 8.952981
5 1 5 9.900112 10.918042
6 1 6 9.185120 10.625667
7 1 7 9.620793 10.316724
8 1 8 11.718397 9.256835
9 1 9 10.034793 11.634023
10 2 1 11.634331 9.746453
11 2 2 9.195410 7.665265
12 2 3 11.323344 8.279968
13 2 4 9.617224 11.792142
14 2 5 9.360307 11.166162
15 2 6 7.963320 11.325801
16 2 7 8.022093 8.568503
17 2 8 10.440788 9.026129
18 2 9 10.841408 10.033346
19 3 1 11.618665 10.179793
20 4 1 10.975061 9.503309
21 4 2 10.209288 12.409656
>
同样,我们注意到每次迭代中的最后一行(9、18、19 和 21)的值都大于 10。a
b
请注意,这种方法未能利用 R 中的向量化运算,这意味着不是每次调用 生成 1,000 个随机数,而是基于 的代码在每次调用 时生成一个随机数。由于是资源密集型函数,因此需要最小化执行次数的代码。rnorm()
while()
rnorm()
rnorm()
rnorm()
上一个:R:逻辑条件未得到尊重
下一个:R:正确调用包含“i”的变量
评论
a
b