传入Formula参数时,lapply结合lm估计复权模型报错问题
复权回归模型函数报错问题
问题背景
我想用复权(replicate weights)估计回归模型,通过每组复权跑同一模型来得到正确的标准误。为避免重复编写循环,我写了两个函数:trythis在lapply内直接指定公式可正常运行,但将公式作为参数传入的trythis2却报错,提示object 'weightsdata' not found。
可复现代码
数据生成代码
library(tidyverse) set.seed(123) lm.dat <- data.frame(id=1:500, x1=sample(1:100, replace=T, size=500), x2=runif(n=500, min=0, max=20)) %>% mutate(y=0.2*x1+1.5*x2+rnorm(n=500, mean=0, sd=5)) repweights <- data.frame(id=1:500) set.seed(123) for (i in 1:200) { repweights[,i+1] <- runif(n=500, min=0, max=10) names(repweights)[i+1] <- paste0("hrwgt", i) }
函数定义
trythis <- function(data, weightsdata, weightsN){ rep <- as.list(1:weightsN) res <- lapply(rep, function(x) lm(data=data, formula=y~x1+x2, weights=weightsdata[,x])) return(res) } results1 <- trythis(data=lm.dat, weightsdata=repweights[-1], weightsN=200) trythis2 <- function(LMformula, data, weightsdata, weightsN){ rep <- as.list(1:weightsN) res <- lapply(rep, function(x) lm(data=data, formula=LMformula, weights=weightsdata[,x])) return(res) }
报错情况
调用trythis2时出现以下错误:
trythis2(LMformula = y~x1+x2, data=lm.dat, weightsN=200, weightsdata = repweights[-1]) # Error in eval(extras, data, env) : object 'weightsdata' not found
问题原因
这是公式的环境绑定问题:当你把LMformula作为参数传入函数时,它的环境是全局环境(或调用trythis2的外部环境);而lapply内的匿名函数执行时,lm会尝试在公式绑定的环境中查找weightsdata,但weightsdata是trythis2的局部变量,不在公式的环境范围内,因此找不到。
而trythis里直接写y~x1+x2,这个公式是在trythis函数内部创建的,环境绑定到trythis的函数环境,所以能正常找到weightsdata。
解决方案
方法1:重新绑定公式的环境
将传入的LMformula的环境设置为当前函数的环境,让lm能找到局部变量weightsdata:
trythis2 <- function(LMformula, data, weightsdata, weightsN){ # 把公式的环境绑定到当前函数环境 environment(LMformula) <- environment() rep <- as.list(1:weightsN) res <- lapply(rep, function(x) lm(data=data, formula=LMformula, weights=weightsdata[,x])) return(res) }
方法2:将权重临时加入数据框
每次迭代把当前权重列加入到输入数据中,直接用列名指定权重,避开环境查找问题:
trythis2 <- function(LMformula, data, weightsdata, weightsN){ rep <- as.list(1:weightsN) res <- lapply(rep, function(x) { # 将当前权重临时加入数据框 temp_data <- cbind(data, w = weightsdata[,x]) lm(data=temp_data, formula=LMformula, weights=w) }) return(res) }
两种方法均可正常运行,生成包含200个回归模型的结果列表。
内容的提问来源于stack exchange,提问作者andreasf
相关产品推荐
相关产品推荐

