首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在应用中的函数中循环

在应用中的函数中循环
EN

Stack Overflow用户
提问于 2021-01-26 18:12:04
回答 1查看 169关注 0票数 0

我有这样的数据:

代码语言:javascript
复制
df <- data.frame(A=1:10, B=3, C=17)

我想对dataframe的每一行应用一个函数,它迭代地根据行的值计算一个值。我使用的原始数据和函数要复杂得多,但是这里的结构和问题是相同的。

例如,我使用以下函数迭代计算A的平方根:

代码语言:javascript
复制
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]]
             }

然后,我可以通过以下方法获得一行的计算值:

代码语言:javascript
复制
fun_iter(df[3, ])

它正确地返回3的平方根。此外,我可以使用如下的for循环循环数据帧:

代码语言:javascript
复制
for (i in 1:nrow(df)) {
  print(fun_iter(df[i, ]))
}

它给出了列"A“中所有值的平方根。但是,由于我有相当大的数据格式,所以我希望使用"apply“或"map”或类似的高效方法来获得输出,但它总是返回以下错误:

代码语言:javascript
复制
apply(df, 2, fun_iter)

Error in while (diff > 0.01) { : Missing Value, where TRUE/FALSE is needed

因此,不知何故,apply似乎在计算函数中的"while“条件时遇到了问题。"map“、"mapply”、"do.call“也是如此。任何解决这个问题的提示都是非常感谢的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-26 19:04:50

根据注释中的说明,我们可以使用其中之一迭代行。对于那些有名字的解决方案,如果不想要的话,可以在结果上使用unname

代码语言:javascript
复制
# 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

代码语言:javascript
复制
# 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)。例如,

代码语言:javascript
复制
# 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"],我们可以避免这种情况。

代码语言:javascript
复制
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,而且它还避免了上面讨论的问题。我们保留了原名,但您可以考虑使用较短的名称。函数中使用的过于冗长的命名几乎没有增加什么,而且实际上掩盖了代码。

代码语言:javascript
复制
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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65906904

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档