R while在apply中的函数中循环
我有这样一个数据帧:R while在apply中的函数中循环,r,while-loop,apply,R,While Loop,Apply,我有这样一个数据帧: df <- data.frame(A=1:10, B=3, C=17) for (i in 1:nrow(df)) { print(fun_iter(df[i, ])) } 正确返回3的平方根。此外,我可以使用for循环循环遍历数据帧,如下所示: df <- data.frame(A=1:10, B=3, C=17) for (i in 1:nrow(df)) { print(fun_iter(df[i, ])) } 这给了我列“A”中所有值的平
df <- data.frame(A=1:10, B=3, C=17)
for (i in 1:nrow(df)) {
print(fun_iter(df[i, ]))
}
正确返回3的平方根。此外,我可以使用for循环循环遍历数据帧,如下所示:
df <- data.frame(A=1:10, B=3, C=17)
for (i in 1:nrow(df)) {
print(fun_iter(df[i, ]))
}
这给了我列“A”中所有值的平方根。但是,由于我有一个相当大的数据帧,我想使用“应用”或“映射”或类似的高效方式来获取输出,但它总是返回以下错误:
apply(df, 2, fun_iter)
Error in while (diff > 0.01) { : Missing Value, where TRUE/FALSE is needed
因此,似乎apply在评估函数中的“while”条件时遇到了问题。“map”、“mapply”、“do.call”也会发生同样的情况。非常感谢对解决此问题的任何提示。根据评论中的说明,我们可以使用其中一个对行进行迭代。对于那些有名称的解决方案,如果不需要,请在结果上使用
unname
# 1
nr <- nrow(df)
sapply(1:nr, function(i) fun_iter(df[i, ]))
## [1] 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## [9] 3.000000 3.162278
# 2
do.call("c", by(df, 1:nr, fun_iter, simplify = FALSE))
## 1 2 3 4 5 6 7 8
## 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## 9 10
## 3.000000 3.162278
# 3
sapply(split(df, 1:nr), fun_iter)
## 1 2 3 4 5 6 7 8
## 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## 9 10
## 3.000000 3.162278
CRAN上还有许多列表理解包(comprer、eList、listcmpr)。比如说,
# 5
library(listcompr)
gen.vector(fun_iter(df[i, ]), i = 1:nr)
## [1] 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## [9] 3.000000 3.162278
# 6
library(comprehenr)
to_vec(for(i in 1:nr) fun_iter(df[i, ]))
## [1] 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## [9] 3.000000 3.162278
古老的
我们遵循问题下方的注释,但我们只传递df[“A”]
,因为apply
将强制输入到普通向量,如果有任何列是空的,则可能导致行变为字符。通过使用df[“A”]
我们可以避免这种情况
apply(df["A"], 1, fun_iter)
## [1] 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## [9] 3.000000 3.162278
如果将函数编写为接受A
而不是df
,则会更简单,而且由于列不需要命名为A,因此也可以避免上述问题。我们已经留下了原来的名字,但你可以考虑使用更短的名字。函数中使用的过于冗长的命名只会增加很少的内容,实际上会使代码变得模糊
fun_iter2 <- function(A, diff = 10) {
sqrt_iter <- A
while(diff > 0.01) {
sqrt_iter_new <- (sqrt_iter + A / sqrt_iter) / 2
diff <- abs(sqrt_iter - sqrt_iter_new)
sqrt_iter <- sqrt_iter_new
}
sqrt_iter
}
sapply(df$A, fun_iter2)
## [1] 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## [9] 3.000000 3.162278
fun\u iter2apply
只是一个伪装的循环。它不会给你矢量化带来的同样的速度提升(假设矢量化是可能的)。即使你得到了正确的细节,你也可能会对结果感到失望。试试这个应用(df,1,fun_iter)它很有效,谢谢!我似乎对apply中“1”和“2”的方向感到困惑,尽管使用了多年。可能与以下答案中描述的输入格式有关。谢谢@约翰·科尔曼:谢谢,很遗憾,矢量化是不可能的。我更喜欢将
应用于for循环,这样我就不必将每个迭代步骤写入预定义的数据框架。我使用了df[“a”],因为我有多个变量作为输入(到目前为止有20个,它将变得更多)。因此,我认为将整个df作为输入是最容易的。但正如您所指出的,“应用”将其更改为character,以您的方式提供变量可能是不可避免的。谢谢请参阅修改后的答案。感谢您提供备选方案<代码>应用(df,1,fun_iter)对我来说是删除带有名称的向量后最快的。sapply
函数的速度要慢得多(慢了18倍!),这可能与数据存储在数据帧中并首先将其转换为矩阵有关。如果矩阵都是数值的,你可以从一开始就尝试将它存储在矩阵中。另外,如果你将矩阵存储为转置,然后使用m,那么矩阵是逐列存储的
fun_iter2 <- function(A, diff = 10) {
sqrt_iter <- A
while(diff > 0.01) {
sqrt_iter_new <- (sqrt_iter + A / sqrt_iter) / 2
diff <- abs(sqrt_iter - sqrt_iter_new)
sqrt_iter <- sqrt_iter_new
}
sqrt_iter
}
sapply(df$A, fun_iter2)
## [1] 1.000000 1.414216 1.732051 2.000000 2.236069 2.449494 2.645767 2.828427
## [9] 3.000000 3.162278