2011-11-21 1 views
6

R에 이상한 문제가있어서 잘 풀리지 못합니다.모델 수식을 다른 함수로 전달할 때 개체를 찾을 수 없음 오류

R에서 단계별 절차로 선택한 모델에 대해 K 배 교차 유효성 검사를 수행하는 함수를 작성하려고했습니다. (단계별 절차의 문제점을 알고 있는데, 이는 비교 목적으로 만 사용되었습니다 :)

이제는 함수 매개 변수 (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) 

어떤 생각이 들었습니까?

+2

'step (lm.1, direction = direction, trace = 0)'이 이미 알고있는 것처럼 'datas.train'을 찾을 수없는 범위 지정 문제가있는 것 같습니다. 나는 그 문제의 원인을 직접 볼 수 없다. 'datas.train'을 전역 변수로 할당하는 것은 해결 방법이지만, 특히 만족스러운 방법은 아닙니다 ('datas.train << datas [-xval.idx [[j]]]). 아마도 이것은 StackOverflow로 마이그레이션해야합니까? – jthetzel

+0

특히'step()'에서'add1 (fit, scope $ add, scale = scale, trace = trace, k = k, ...)'를 호출하면 에러가 발생하고,'add1()'은' stats ::: add1.lm'. – jthetzel

+0

@jthetel, 참으로. 한 가지 방법은 비슷한 문제를 해결했지만 루프 내에서 다른 함수 호출을 위해 전역 적으로 할당하는 것이 었습니다. – dcl

답변

10

수식을 만들 때 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 
+0

그게 효과가있다. 나는이 환경에 대해 조사해야 할 것이다. :) 건배. – dcl

4

또 다른 문제 character (문자열 vector)을 formula 대신 lm으로 전달하면됩니다. vector에는 environment이 없으므로 lmcharacterformula으로 변환 할 때 로컬 환경에 자동으로 할당되는 대신 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 변수에 weights이라는 이름을 사용하면 디버그가 더욱 어려워집니다. 이 경우, lm 때문에 가중치가 기지에서 함수 weights()에 기본값을 반대 찾을 수 없습니다 따라서 더 낯선 오류를 던지는 :

Error in model.frame.default(formula = f, data = data, weights = weights, : 
    invalid type (closure) for variable '(weights)' 

은 저를했다 몇 시간 안 함 이것을 알아 내십시오.