2011-11-21 11 views
6

Mam dziwny problem z R, którego nie mogę wymyślić.Nie znaleziono błędu obiektu podczas przekazywania formuły modelu do innej funkcji

Próbowałem napisać funkcję, która wykonuje K-krotność sprawdzania poprawności dla modelu wybranego przez procedurę krokową w R. (Jestem świadomy problemów z procedurami krokowymi, to jest wyłącznie w celach porównawczych) :)

Problem polega na tym, że jeśli zdefiniuję parametry funkcji (linmod, k, kierunek) i uruchomię zawartość funkcji, działa ona bezbłędnie. ALE, jeśli uruchomię go jako funkcję, pojawia się błąd informujący, że nie można odnaleźć obiektu datas.train.

Próbowałem już przejść przez funkcję z debug(), a obiekt wyraźnie istnieje, ale R mówi, że tak nie jest, gdy faktycznie uruchomię tę funkcję. Jeśli po prostu pasuję do modelu za pomocą lm(), to działa dobrze, więc uważam, że jest to problem z funkcją kroku w pętli, podczas gdy wewnątrz funkcji. (spróbuj skomentować polecenie kroku i ustawić predykcje na te ze zwykłego modelu liniowego.)

#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) 

Jakieś przemyślenia?

+2

Wydaje się, że istnieje problem z zakresu, w którym 'step (lm.1, direction = direction, trace = 0)' nie może znaleźć 'datas.train', jak już wiesz. Nie widzę przyczyny problemu. Przypisanie 'datas.train' jako zmiennej globalnej jest rozwiązaniem, ale nie jest szczególnie satysfakcjonujące (' datas.train << - datas [-xval.idx [[j]],] '). Być może należy to przenieść do StackOverflow? – jthetzel

+0

W szczególności wywołanie 'add1 (dopasowanie, zasięg $ add, skala = skala, trace = trace, k = k, ...)' w 'step()' powoduje zgłoszenie błędu, gdzie 'add1()' jest ' statystyki ::: add1.lm'. – jthetzel

+0

@jthetzel, Rzeczywiście. Jednym ze sposobów rozwiązania podobnego problemu, ale dla innego wywołania funkcji w pętli było przypisanie go globalnie. – dcl

Odpowiedz

10

Po utworzeniu formuły lm.cars przypisano własne środowisko. To środowisko pozostaje z formułą, chyba że wyraźnie ją zmienisz. Tak więc po wyodrębnieniu formuły za pomocą funkcji formula uwzględniane jest oryginalne środowisko modelu.

ja nie wiem, czy używam poprawną terminologię tutaj, ale myślę, że trzeba wyraźnie zmienić środowisko dla wzoru wewnątrz swojej funkcji:

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

To działa. Będę musiał zaglądać do tego środowiska. :) Twoje zdrowie. – dcl

4

Innym problemem, który może być przyczyną tego jest jeśli przekazujemy character (ciąg vector) do lm zamiast formula. vector s nie ma environment, a gdy lm konwertuje character na formula, najwyraźniej nie ma również environment zamiast automatycznego przypisywania lokalnego środowiska. Jeśli ktoś używa obiektu jako ciężaru, który nie znajduje się w argumencie danych data.frame, ale jest w lokalnym argumencie funkcji, otrzymuje się błąd not found. Takie zachowanie nie jest łatwe do zrozumienia. To prawdopodobnie błąd.

Oto minimalny odtwarzalny przykład. Ta funkcja przyjmuje nazwę data.frame, dwie nazwy zmiennych i wektor wag.

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) 

i Test:

> 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 

Jest to bardzo subtelne bug. Jeśli wejdzie się w środowisko funkcji z browser, można zobaczyć wektor wagowy w porządku, ale jakoś nie można go znaleźć w wywołaniu lm!

Błąd staje się jeszcze trudniejszy do debugowania, jeśli użyto nazwy zmiennej. W tym przypadku, ponieważ nie można znaleźć lm wagi obiektu, domyślnie funkcji weights() z bazy więc rzuca nawet obcy błąd:

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

nie pytaj ile godzin zajęło mi wymyśl to.

Powiązane problemy