Evaluating a maximum likelihood expression using datamasks in R
我正在尝试使用数据掩码评估最大似然表达式。这个想法是允许在函数内按名称调用参数和变量,同时避免多次调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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) |
这很好用,但是,我必须调用
现在,仅创建数据掩码并尝试评估对数似然函数不起作用:
1 2 | mask <- as_data_mask(db) eval_tidy(quo(maxLik::maxLik(ll_lik, start = param)), mask) |
它无法访问数据掩码 (
1 | eval_tidy(quo(ll_lik(param)), mask) |
但这有效:
1 | eval_tidy(quo(x*3), mask) |
所以,我开始怀疑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 | eval_tidy(call_stack(), data = new_mask) |
确实,如果我没看错的话,函数的父级就是全局环境。
1 2 3 4 | █ 1. ├─rlang::eval_tidy(call_stack(), data = new_mask) 2. └─global::call_stack() 3. └─lobstr::cst() |
但是,我不知道如何进行这项工作。任何帮助深表感谢。
奖励:如果我能够在
一种选择是创建一个package器,将
1 2 3 4 5 | llwrap <- function(param) { eval( body(ll_lik), db ) } model <- maxLik::maxLik(llwrap, start=param) # Works |
编辑解决您的问题:是的,
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |