我对R有一个奇怪的问题,我似乎无法解决。
我已经尝试编写一个函数,对R中逐步过程选择的模型执行K折交叉验证。(我知道逐步过程的问题,它纯粹用于比较目的):)< / p>
现在问题是,如果我定义函数参数(linmod,k,direction)并运行函数的内容,它可以完美地工作。但是,如果我将它作为一个函数运行,我会收到一条错误,指出无法找到datas.train对象。
我尝试使用debug()逐步执行该函数,并且该对象显然存在,但R表示当我实际运行该函数时它不会。如果我只是使用lm()拟合模型,它工作正常,所以我认为这是循环中的step函数的问题,而在函数内部。 (尝试注释掉步骤命令,并将预测设置为普通线性模型的预测。)
#CREATE A LINEAR MODEL TO TEST FUNCTION
lm.cars <- lm(mpg~.,data=mtcars,x=TRUE,y=TRUE)
#THE FUNCTION
cv.step <- function(linmod,k=10,direction="both"){
response <- linmod$y
dmatrix <- linmod$x
n <- length(response)
datas <- linmod$model
form <- formula(linmod$call)
# generate indices for cross validation
rar <- n/k
xval.idx <- list()
s <- sample(1:n, n) # permutation of 1:n
for (i in 1:k) {
xval.idx[[i]] <- s[(ceiling(rar*(i-1))+1):(ceiling(rar*i))]
}
#error calculation
errors <- R2 <- 0
for (j in 1:k){
datas.test <- datas[xval.idx[[j]],]
datas.train <- datas[-xval.idx[[j]],]
test.idx <- xval.idx[[j]]
#THE MODELS+
lm.1 <- lm(form,data= datas.train)
lm.step <- step(lm.1,direction=direction,trace=0)
step.pred <- predict(lm.step,newdata= datas.test)
step.error <- sum((step.pred-response[test.idx])^2)
errors[j] <- step.error/length(response[test.idx])
SS.tot <- sum((response[test.idx] - mean(response[test.idx]))^2)
R2[j] <- 1 - step.error/SS.tot
}
CVerror <- sum(errors)/k
CV.R2 <- sum(R2)/k
res <- list()
res$CV.error <- CVerror
res$CV.R2 <- CV.R2
return(res)
}
#TESTING OUT THE FUNCTION
cv.step(lm.cars)
有什么想法吗?
答案 0 :(得分:15)
创建公式时,lm.cars
为in分配了自己的环境。除非您明确更改,否则此环境将保留公式。因此,当您使用formula
函数提取公式时,将包含模型的原始环境。
我不知道我是否在这里使用了正确的术语,但我认为您需要明确更改函数内部公式的环境:
cv.step <- function(linmod,k=10,direction="both"){
response <- linmod$y
dmatrix <- linmod$x
n <- length(response)
datas <- linmod$model
.env <- environment() ## identify the environment of cv.step
## extract the formula in the environment of cv.step
form <- as.formula(linmod$call, env = .env)
## The rest of your function follows
答案 1 :(得分:8)
另一个可能导致此问题的问题是,如果将character
(字符串vector
)传递给lm
而不是formula
。 vector
没有environment
,因此当lm
将character
转换为formula
时,它显然也没有environment
而不是data.frame
自动分配本地环境。如果然后使用对象作为不在数据参数not found
中的权重,但是在本地函数参数中,则会得到data.frame
错误。这种行为不是很容易理解。这可能是一个错误。
这是一个可重复性最小的例子。该函数采用residualizer = function(data, x, y, wtds) {
#the formula to use
f = "x ~ y"
#residualize
resid(lm(formula = f, data = data, weights = wtds))
}
residualizer2 = function(data, x, y, wtds) {
#the formula to use
f = as.formula("x ~ y")
#residualize
resid(lm(formula = f, data = data, weights = wtds))
}
d_example = data.frame(x = rnorm(10), y = rnorm(10))
weightsvar = runif(10)
,两个变量名和一个权重向量来使用。
> residualizer(data = d_example, x = "x", y = "y", wtds = weightsvar)
Error in eval(expr, envir, enclos) : object 'wtds' not found
> residualizer2(data = d_example, x = "x", y = "y", wtds = weightsvar)
1 2 3 4 5 6 7 8 9 10
0.8986584 -1.1218003 0.6215950 -0.1106144 0.1042559 0.9997725 -1.1634717 0.4540855 -0.4207622 -0.8774290
并测试:
browser
这是一个非常微妙的错误。如果用lm
进入函数环境,可以看到权重向量就好了,但在weights
调用中找不到它!
如果使用名称lm
作为权重变量,则该错误变得更难调试。在这种情况下,由于weights()
无法找到权重对象,因此默认为 base 中的函数Error in model.frame.default(formula = f, data = data, weights = weights, :
invalid type (closure) for variable '(weights)'
,从而引发更奇怪的错误:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)/$ /$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
不要问我花了多少时间来解决这个问题。