Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在R中使用数据掩码计算最大似然表达式_R_Eval_Tidyeval - Fatal编程技术网

在R中使用数据掩码计算最大似然表达式

在R中使用数据掩码计算最大似然表达式,r,eval,tidyeval,R,Eval,Tidyeval,我试图使用数据掩码计算最大似然表达式。其思想是允许在函数中按名称调用参数和变量,同时避免多次调用attach()和detach()。这是一个非常简单的小示例,实际函数非常大和复杂 set.seed(1) # Data db <- data.frame( x = runif(10), y = runif(10), z = sample(c(0, 1), 10, replace = TRUE) ) # Log likelihood function ll_lik <- f

我试图使用数据掩码计算最大似然表达式。其思想是允许在函数中按名称调用参数和变量,同时避免多次调用
attach()
detach()
。这是一个非常简单的小示例,实际函数非常大和复杂

set.seed(1)

# Data
db <- data.frame(
  x = runif(10),
  y = runif(10),
  z = sample(c(0, 1), 10, replace = TRUE)
)

# Log likelihood function
ll_lik <- function(param) {
  pr_1 <- 1 / (1 + exp(-(param[1]*x - param[2]*y)))
  pr_2 <- 1 - pr_1
  lik <- z * pr_1 + (1 - z) * pr_2
  log(lik)
}

# Parameters
param <- c(p1 = 0.1, p2 = 0.2)

# Run the model with attach()/detach()
attach(db)
model <- maxLik::maxLik(ll_lik, start = param)
detach(db)
summary(model)

它无法访问数据掩码中的对象(
fnOrig(θ,…)中的错误:未找到对象“x”
)。也许问题出在
maxLik
,但我甚至无法评估
ll_-lik()
,这会产生相同的错误:

eval_tidy(quo(ll_lik(param)), mask)
但这是可行的:

eval_tidy(quo(x*3), mask)
因此,我开始怀疑
ll_lik()
具有“错误”的父级,这就是为什么我的数据掩码可能不在函数的搜索路径中,因此它无法找到变量。现在,as_data_mask()的帮助部分提供了一些示例,说明如何通过创建顶级、中级和底层环境来“嵌套”环境。好的,让我们看看我是否可以创建我的函数作为数据掩码结构的一部分:

call_stack <- function() {lobstr::cst()}

# Create a new environment (child of empty) that takes a list of objects to populate it
top <- new_environment(list(ll_lik = ll_lik, call_stack = call_stack))

# Create a child of the "top" environment"
middle <- env(top)

# Create a child of the "middle environment and add the data object to it
bottom <- env(middle, db=db)

# Create a data_mask where the bottom contains the masking elements and the top
# the last element of the data_mask.
new_mask <- new_data_mask(bottom, top = top)
事实上,如果我读对了,函数的父函数是全局环境

    █
 1. ├─rlang::eval_tidy(call_stack(), data = new_mask)
 2. └─global::call_stack()
 3.   └─lobstr::cst()
然而,我对如何使这项工作起作用感到困惑。非常感谢您的帮助


BONOUS:如果我能够在
maxLik
中按名称调用参数,而不调用
attach()
/
detach()
,那就太棒了

一个选项是创建一个包装器,以
db
作为上下文,将
ll_lik
的主体作为表达式进行计算:

llwrap <- function(param) {
  eval( body(ll_lik), db )
}

model <- maxLik::maxLik(llwrap, start=param)      # Works

你好我不是
datamasks
方面的专家,因此我无法评论如何使用这种方法访问
db
中的对象,但我只是想知道一个(可能是愚蠢的)问题。我在
maxLik
函数的帮助页面上读到以下句子:“…:[…]优化器未使用的参数被转发到
logLik
grad
hess
”。我认为您可以使用参数
x
y
z
定义
ll_lik
函数,然后使用
db$x
或使用
with
函数传递相应的值。如果你愿意,我可以用这种方法提供更详细的答案。是的,
attach()
的使用是为了避免将
db$
放在所有变量前面(在某些情况下有很多变量)。我想在遇到类似问题之前,我已经尝试过使用
with()
函数。如果我正确理解
with()
,它的功能确实类似于数据掩码,但数据掩码可以包含数据、函数和您可能希望在log函数中访问的其他对象。我可能也误解了这一点。很有趣。我不知道
body()
。这种方法是否也可以扩展以允许按名称调用
param
的元素,而不是
param[1]
param[2]
等?非常感谢您提供最新的答案。这无疑是朝着正确方向迈出的一步。我将在更大的代码上下文中稍微研究一下您的解决方案,看看它是如何工作的。干杯。@user63230:从技术上讲,这是在创造一个环境
eval()
将把作为第二个参数提供的列表转换为一个环境,在该环境中计算第一个参数(表达式)。这个答案中的eval模式基本上只是一个复杂的
with()
。考虑<代码>(MTCAS,MPG*CYL)< /代码>。通过将表达式存储在变量
e中,所以它只是用于变量屏蔽,类似于
mutate
so。。。。我关于创建环境的意思是,您不必显式地创建一个环境。例如,在表达式求值的上下文中,您可以认为列表、数据帧和环境是可互换的。所以,是的,这是真的:我们没有显式地调用
new.env()
。但是,我们显式地使用
c(as.list(db)、as.list(param))
创建一个列表,然后通过
eval()
隐式地将其转换为一个环境。
    █
 1. ├─rlang::eval_tidy(call_stack(), data = new_mask)
 2. └─global::call_stack()
 3.   └─lobstr::cst()
llwrap <- function(param) {
  eval( body(ll_lik), db )
}

model <- maxLik::maxLik(llwrap, start=param)      # Works
ll_expr <- rlang::expr({                       # An expression, not a function
  pr_1 <- 1 / (1 + exp(-(p1*x - p2*y)))        # <-- now using p1, p2
  pr_2 <- 1 - pr_1
  lik <- z * pr_1 + (1 - z) * pr_2
  log(lik)
})

llwrap2 <- function(param) {
  ctx <- c( as.list(db), as.list(param) )      # Combine param and db into one context
  eval( ll_expr, ctx )                         # No longer need body()
}

model <- maxLik::maxLik(llwrap2, start=param)  # Works