我有这样的数据:
df <- data.frame(A=1:10, B=3, C=17)我想对dataframe的每一行应用一个函数,它迭代地根据行的值计算一个值。我使用的原始数据和函数要复杂得多,但是这里的结构和问题是相同的。
例如,我使用以下函数迭代计算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, ])它正确地返回3的平方根。此外,我可以使用如下的for循环循环数据帧:
for (i in 1:nrow(df)) {
print(fun_iter(df[i, ]))
}它给出了列"A“中所有值的平方根。但是,由于我有相当大的数据格式,所以我希望使用"apply“或"map”或类似的高效方法来获得输出,但它总是返回以下错误:
apply(df, 2, fun_iter)
Error in while (diff > 0.01) { : Missing Value, where TRUE/FALSE is needed因此,不知何故,apply似乎在计算函数中的"while“条件时遇到了问题。"map“、"mapply”、"do.call“也是如此。任何解决这个问题的提示都是非常感谢的。
发布于 2021-01-26 19:04:50
根据注释中的说明,我们可以使用其中之一迭代行。对于那些有名字的解决方案,如果不想要的话,可以在结果上使用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上也有许多列表理解包(全面、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.162278https://stackoverflow.com/questions/65906904
复制相似问题