首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用` with `函数调用`eval`?

如何使用` with `函数调用`eval`?
EN

Stack Overflow用户
提问于 2020-02-20 23:48:44
回答 2查看 178关注 0票数 3

有了一个lm对象,我需要根据它的变量创建一个函数,该变量表示为字符向量。我曾尝试使用evalexpr的组合来创建一个f函数,该函数将进一步用于后者的objnlm优化。

代码语言:javascript
运行
复制
library(tidyverse)
df <- drop_na(airquality)
model <- lm(Ozone~. - Temp, data = df, x=TRUE, y=TRUE)
base_vars <- all.vars(formula(model)[-2])
k <- length(base_vars)

f <- function(base_df, x, y, parms) {
  with(base_df, parms[1] + 
         eval(expr(paste(paste(paste0('parms[', 2:(k+1), ']'), base_vars, sep = '*'), collapse = '+'))) + 
         log(parms[k+2] * (x - parms[k+3] ^ 2)))
}
obj <- function(parms, y, x) mean((residuals(model) - f(df, x, y, parms))^2) 
fit <- with(data, nlm(obj, c(0, 0, 0, 0, 0, 0, 0), y = e, x = x))

但是调用f(model$x, df$Temp, model$y, c(0, 0, 0, 0, 0, 0, 0))会导致以下错误:

代码语言:javascript
运行
复制
Error in eval(substitute(expr), data, enclos = parent.frame()) : 
  numeric 'envir' arg not of length one 
4.
eval(substitute(expr), data, enclos = parent.frame()) 
3.
with.default(base_df, parms[1] + eval(expr(paste(paste(paste0("parms[", 
    2:(k + 1), "]"), base_vars, sep = "*"), collapse = "+"))) + 
    log(parms[k + 2] * (x - parms[k + 3]^2))) 
2.
with(base_df, parms[1] + eval(expr(paste(paste(paste0("parms[", 
    2:(k + 1), "]"), base_vars, sep = "*"), collapse = "+"))) + 
    log(parms[k + 2] * (x - parms[k + 3]^2))) 
1.
f(model$x, df$Temp, model$y, c(0, 0, 0, 0, 0, 0, 0))

我相信在eval环境和with函数所隐含的环境之间可能存在冲突,但无法找出原因。有什么想法吗?如何为变量模型创建自定义函数f

f(model$x, df$Temp, model$y, c(0, 0, 0, 0, 0, 0, 0))的预期输出为:

代码语言:javascript
运行
复制
with(base_df, parms[1]+parms[2]*Solar.R+parms[3]*Wind+parms[4]*Temp+parms[5]*Month+
              parms[6]*Day+log(parms[7] * (Temp - parms[8] ^ 2)))

但对于不同的模型,它可能是这样的:

代码语言:javascript
运行
复制
with(base_df, 
     parms[1]+parms[2]*var1+parms[3]*var2+log(parms[4]*(var3-parms[5]^2)))

所以每次调用的变量和参数的数量都是不同的。

EN

Stack Overflow用户

发布于 2020-03-08 03:24:05

我认为@Roland给了你一个很好的回答,涵盖了你的实际问题。我正在根据问题的标题来隔离我认为你特别问的问题,没有评论这是不是一个好主意。它可能不在这个用例中。

但是你更想要的是来自rlangeval_tidy()。我将::函数符号留在其中,以便很容易看出这里使用的是什么包。

注意,我修复了代码中的一些似乎是错误的东西。由于日志的原因,我还使用全一而不是零在parms中进行测试。

代码语言:javascript
运行
复制
library(rlang)
library(tidyr)

# dropped y since it was an unused argument
f <- function(base_df, x, parms) {
  # set an expression to evaluate using parse_expr()
  .f <- rlang::parse_expr(paste(paste(paste0('parms[', 2:(k+1), ']'),
                                      base_vars, sep = '*'), collapse = '+'))

  # use eval_tidy() with the data mask  
  y_part1 <- rlang::eval_tidy(.f, data = base_df)
  y_part2 <- log(parms[k + 2] * (x - parms[k + 3] ^ 2))

  parms[1] + y_part1 + y_part2
}

# using your code
df <- tidyr::drop_na(airquality)
model <- lm(Ozone~. - Temp, data = df, x=TRUE, y=TRUE)
base_vars <- all.vars(formula(model)[-2])
k <- length(base_vars)

# changed to all ones, I think this is what you wanted for length
parms <- rep(1, k + 3)

method_1 <- f(df, df$Temp, parms)

method_2 <- with(df, parms[1]+parms[2]*Solar.R+parms[3]*Wind+parms[4]*Temp+parms[5]*Month+
                   parms[6]*Day+log(parms[7] * (Temp - parms[8] ^ 2)))


all.equal(method_1, method_2)
# [1] TRUE
票数 1
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60323754

复制
相关文章

相似问题

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