2011-11-21 42 views
6

Tôi gặp vấn đề lạ với R mà tôi không thể làm việc.Lỗi đối tượng không tìm thấy khi chuyển công thức mô hình sang chức năng khác

Tôi đã cố gắng viết một hàm thực hiện xác thực chéo K cho một mô hình được chọn theo thủ tục stepwise trong R. (Tôi biết các vấn đề với thủ tục từng bước, nó hoàn toàn cho mục đích so sánh) :)

Bây giờ vấn đề là, nếu tôi xác định các tham số hàm (linmod, k, direction) và chạy nội dung của hàm, nó hoạt động hoàn hảo. NHƯNG, nếu tôi chạy nó như là một hàm, tôi nhận được một lỗi nói rằng đối tượng datas.train không thể được tìm thấy.

Tôi đã thử bước qua chức năng với debug() và đối tượng rõ ràng tồn tại, nhưng R nói nó không khi tôi thực sự chạy hàm. Nếu tôi chỉ phù hợp với một mô hình bằng cách sử dụng lm() nó hoạt động tốt, vì vậy tôi tin rằng đó là một vấn đề với chức năng bước trong vòng lặp, trong khi bên trong một chức năng. (hãy thử nhận xét ra lệnh bước và đặt các dự đoán cho những người từ mô hình tuyến tính thông thường.)

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

Bất kỳ suy nghĩ nào?

+2

Dường như có vấn đề về phạm vi, trong đó 'bước (lm.1, hướng = hướng, dấu vết = 0)' không thể tìm thấy 'datas.train', như bạn đã biết. Tôi không thể thấy nguyên nhân của vấn đề. Việc gán 'datas.train' làm biến toàn cầu là một work-around, nhưng không phải là một biến đặc biệt thỏa mãn (' datas.train << - datas [-xval.idx [[j]],] '). Có lẽ điều này nên được di chuyển đến StackOverflow? – jthetzel

+0

Cụ thể, lệnh gọi 'add1 (phù hợp, phạm vi $ add, scale = scale, trace = trace, k = k, ...)' trong 'step()' ném lỗi, trong đó 'add1()' là ' số liệu thống kê ::: add1.lm'. – jthetzel

+0

@jthetzel, Thật vậy. Một cách tôi giải quyết một vấn đề tương tự nhưng đối với một cuộc gọi hàm bên trong một vòng lặp là gán nó trên toàn cầu. – dcl

Trả lời

10

Khi bạn tạo công thức, lm.cars, được chỉ định môi trường riêng. Môi trường này vẫn giữ nguyên công thức trừ khi bạn thay đổi nó một cách rõ ràng. Vì vậy, khi bạn giải nén công thức với hàm formula, môi trường gốc của mô hình được bao gồm.

Tôi không biết nếu tôi đang sử dụng các thuật ngữ chính xác ở đây, nhưng tôi nghĩ rằng bạn cần phải thay đổi một cách rõ ràng môi trường cho các công thức bên trong hàm của bạn:

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

Điều đó có hiệu quả. Tôi sẽ phải xem xét công cụ môi trường này. :) Chúc mừng. – dcl

4

Một vấn đề khác mà có thể gây ra điều này là nếu một người vượt qua một số character (chuỗi vector) đến lm thay vì formula. vector s không có environment và do đó khi lm chuyển đổi character thành formula, dường như cũng không có environment thay vì được tự động gán môi trường cục bộ. Nếu sau đó, một đối tượng sử dụng một đối tượng dưới dạng trọng số không nằm trong đối số dữ liệu data.frame, nhưng nằm trong đối số hàm cục bộ, một lỗi sẽ bị lỗi not found. Hành vi này không phải là rất dễ hiểu. Nó có lẽ là một lỗi.

Đây là ví dụ về khả năng tái sản xuất tối thiểu. Hàm này có một tên là data.frame, hai tên biến và một vectơ có trọng số để sử dụng.

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) 

Và kiểm tra:

> 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 

Đây là một lỗi rất tinh tế. Nếu một người đi vào môi trường chức năng với browser, người ta có thể thấy véc tơ trọng lượng tốt, nhưng bằng cách nào đó không tìm thấy trong cuộc gọi lm!

Lỗi này càng trở nên khó khăn hơn để gỡ lỗi nếu một tên đã sử dụng tên weights cho biến trọng số. Trong trường hợp này, vì lm không thể tìm thấy các trọng đối tượng, nó mặc định chức năng weights() từ cơ sở do đó ném một lỗi thậm chí người lạ:

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

Đừng hỏi tôi bao nhiêu giờ nó đưa tôi đến hiểu ra điều này.

Các vấn đề liên quan