R中存储方程右侧表达式计算对数似然时报未找到对象错误的咨询
报错核心原因
R对普通赋值语句的执行逻辑是即时求值:你写DA <- b0 + b1*x1 + ...的时候,R会立刻在当前全局环境里检索b0、b1、所有x和d开头的变量,把每个变量对应的数值代入计算出结果,再把这个数值存为DA——它不会自动把“由b和x/d组成的方程结构”当成可后续动态加载的公式存起来。
你现在还没有把待估计的系数b0、b1等定义成环境里存在的数值对象,自然会触发找不到b0的报错。
适配对数似然估计的可行解决方法
因为你要做的是动态调用DA计算对数似然,本质上需要DA能跟着优化器传入的待估系数动态变化,有两种完全适配需求的写法:
方法1:将方程结构存为可延迟求值的表达式
用expression()把方程的结构存下来,赋值时R不会当场检索变量、计算结果,等后续真正需要算DA的时候,再把待估系数、数据列放到临时环境里求值即可:
# 仅存储方程结构,不会触发报错 DA_expr <- expression( b0 + b1 * x1 + b4 * x4 + b5 * x5 + b6 * x6 + b8 * x8 + b9 * x9 + b10 * x10 + b11 * x11 + b12 * x12 + b13 * x13 + b15 * x15 + b17 * x17 + b18 * x18 + b19 * x19 + b20 * x20 + b21 * x21 + b25 * x25 + b27 * x27 + bl2 * d2 + bl3 * d3 + bl5 * d5 + bl6 * d6 + bl7 * d7 + bl8 * d8 + bl9 * d9 + bl10 * d10 + bl11 * d11 )
搭配eval()在对数似然函数内部动态计算DA,示例逻辑:
log_lik <- function(par, dat) { # 按顺序给优化器传入的系数向量命名,和表达式里的变量名一一对应 coef_names <- c("b0","b1","b4","b5","b6","b8","b9","b10","b11","b12", "b13","b15","b17","b18","b19","b20","b21","b25","b27", "bl2","bl3","bl5","bl6","bl7","bl8","bl9","bl10","bl11") coef_list <- as.list(par) names(coef_list) <- coef_names # 构建临时求值环境:同时放入系数和数据列,避免全局变量污染 eval_env <- c(coef_list, as.list(dat)) # 动态计算DA的值 DA <- eval(DA_expr, envir = eval_env) # 代入你写的对数似然公式计算 sum(log((pnorm(DA)^dat$y) * ((1 - pnorm(DA))^(1 - dat$y)))) }
方法2:在对数似然函数内部直接计算DA,不做全局提前赋值
全局环境下提前给DA赋值本身就不符合动态估计的逻辑——因为系数是随优化过程不断变化的,提前存的固定值DA根本没法跟着迭代更新。
更省心的写法是完全跳过全局单独给DA赋值的步骤,每次计算对数似然时在函数内部当场计算DA:
log_lik <- function(par, dat) { # 给系数向量命名 names(par) <- c("b0","b1","b4","b5","b6","b8","b9","b10","b11","b12", "b13","b15","b17","b18","b19","b20","b21","b25","b27", "bl2","bl3","bl5","bl6","bl7","bl8","bl9","bl10","bl11") # 用with()自动加载数据列,减少重复写dat$的冗余 DA <- with(dat, par["b0"] + par["b1"]*x1 + par["b4"]*x4 + par["b5"]*x5 + par["b6"]*x6 + par["b8"]*x8 + par["b9"]*x9 + par["b10"]*x10 + par["b11"]*x11 + par["b12"]*x12 + par["b13"]*x13 + par["b15"]*x15 + par["b17"]*x17 + par["b18"]*x18 + par["b19"]*x19 + par["b20"]*x20 + par["b21"]*x21 + par["b25"]*x25 + par["b27"]*x27 + par["bl2"]*d2 + par["bl3"]*d3 + par["bl5"]*d5 + par["bl6"]*d6 + par["bl7"]*d7 + par["bl8"]*d8 + par["bl9"]*d9 + par["bl10"]*d10 + par["bl11"]*d11 ) sum(log((pnorm(DA)^dat$y) * ((1 - pnorm(DA))^(1 - dat$y)))) }
避坑提示
- 不要直接把
quote(你的表达式)存的结果放到全局环境运行,否则依然会触发找不到b0的报错,必须绑定到自建的临时环境再求值。 - 你最初写的对数似然部分里,
(1-pnorm(DA))^(1-y)的维度对齐要注意:直接写1-y如果y是来自数据框的向量,可能会出现长度不匹配的警告,明确写成1 - dat$y是最稳妥的。 - 如果你的模型是标准Probit线性模型,不需要从零手算对数似然,直接用
glm(y ~ x1 + x4 + ... , data = dat, family = binomial(link = "probit"))就能完成系数估计;如果是带特殊限定的自定义模型,上面的方法可以通用适配。
内容的提问来源于stack exchange,提问作者Maria Kamran
相关产品推荐
相关产品推荐

