while 在 apply 函数中循环
while loop in a function in apply
我有这样一个数据框:
df <- data.frame(A=1:10, B=3, C=17)
我想对数据框的每一行应用一个函数,它根据行的值迭代计算一个值。我的原始数据和我使用的功能要复杂得多,但是结构和问题在这里都是一样的。
例如,我使用以下函数迭代计算 A 的平方根:
fun_iter <- function(df_input, diff=10){
sqrt_iter <- df_input["A"]
while(diff>0.01) {
sqrt_iter_new <- (sqrt_iter + df_input["A"] / sqrt_iter) / 2 # approximate the square-root
diff <- abs(sqrt_iter - sqrt_iter_new) # difference between the iteration steps
sqrt_iter <- sqrt_iter_new # overwrite old value with new iteration
}
sqrt_iter[[1]]
}
然后我可以获得一行的计算值:
fun_iter(df[3, ])
正确地 returns 3 的平方根。此外,我可以使用这样的 for 循环遍历数据帧:
for (i in 1:nrow(df)) {
print(fun_iter(df[i, ]))
}
它给出了“A”列中所有值的平方根。但是,由于我有一个相当大的数据框,我想使用“应用”或“映射”或类似有效的方式来获取输出,但它总是 returns 这个错误:
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
如果我们确定 df 中只有数值,那么我们可以像这样使用 apply
。
# 4
apply(df, 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
CRAN 上还有一些列表理解包(comprehenr、eList、listcompr)。例如,
# 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
我有这样一个数据框:
df <- data.frame(A=1:10, B=3, C=17)
我想对数据框的每一行应用一个函数,它根据行的值迭代计算一个值。我的原始数据和我使用的功能要复杂得多,但是结构和问题在这里都是一样的。
例如,我使用以下函数迭代计算 A 的平方根:
fun_iter <- function(df_input, diff=10){
sqrt_iter <- df_input["A"]
while(diff>0.01) {
sqrt_iter_new <- (sqrt_iter + df_input["A"] / sqrt_iter) / 2 # approximate the square-root
diff <- abs(sqrt_iter - sqrt_iter_new) # difference between the iteration steps
sqrt_iter <- sqrt_iter_new # overwrite old value with new iteration
}
sqrt_iter[[1]]
}
然后我可以获得一行的计算值:
fun_iter(df[3, ])
正确地 returns 3 的平方根。此外,我可以使用这样的 for 循环遍历数据帧:
for (i in 1:nrow(df)) {
print(fun_iter(df[i, ]))
}
它给出了“A”列中所有值的平方根。但是,由于我有一个相当大的数据框,我想使用“应用”或“映射”或类似有效的方式来获取输出,但它总是 returns 这个错误:
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
如果我们确定 df 中只有数值,那么我们可以像这样使用 apply
。
# 4
apply(df, 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
CRAN 上还有一些列表理解包(comprehenr、eList、listcompr)。例如,
# 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