2013-06-30 30 views
7

Tôi muốn chạy qua một vectơ dài các biến giải thích tiềm năng, sẽ thay đổi biến trả lời trên mỗi biến. Thay vì dán cùng nhau công thức mô hình, tôi đang nghĩ đến việc sử dụng reformulate(), as demonstrated here.Bất kỳ cạm bẫy nào khi sử dụng các công thức được lập trình sẵn?

Chức năng fun() bên dưới dường như thực hiện công việc, phù hợp với mô hình mong muốn. Tuy nhiên, lưu ý rằng nó ghi lại trong phần tử gọi của nó là tên của đối tượng công thức được xây dựng thay vì giá trị của nó.

## (1) Function using programatically contructed formula 
fun <- function(XX) { 
    ff <- reformulate(response="mpg", termlabels=XX) 
    lm(ff, data=mtcars) 
} 
fun(XX=c("cyl", "disp")) 
# 
# Call: 
# lm(formula = ff, data = mtcars)     <<<--- Note recorded call 
# 
# Coefficients: 
# (Intercept)   cyl   disp 
# 34.66099  -1.58728  -0.02058 

## (2) Result of directly specified formula (just for purposes of comparison) 
lm(mpg ~ cyl + disp, data=mtcars) 
# 
# Call: 
# lm(formula = mpg ~ cyl + disp, data = mtcars) <<<--- Note recorded call 
# 
# Coefficients: 
# (Intercept)   cyl   disp 
# 34.66099  -1.58728  -0.02058 

Câu hỏi của tôi: Có bất kỳ nguy hiểm trong việc này? Ví dụ, điều này có thể trở thành vấn đề nếu sau này tôi muốn áp dụng update hoặc predict hoặc một số chức năng khác cho đối tượng phù hợp với mô hình, (có thể từ một số môi trường khác)?

Một sự thay thế hơi khó xử hơn, tuy nhiên, hãy ghi lại quyền gọi được ghi lại là sử dụng eval(substitute()). Đây có phải là cách xây dựng an toàn hơn không?

fun2 <- function(XX) { 
    ff <- reformulate(response="mpg", termlabels=XX) 
    eval(substitute(lm(FF, data=mtcars), list(FF=ff))) 
} 
fun2(XX=c("cyl", "disp"))$call 
## lm(formula = mpg ~ cyl + disp, data = mtcars) 
+2

Tôi nghĩ rằng vấn đề sẽ được cẩn thận bằng cách sử dụng 'update' xem [http://stackoverflow.com/questions/13690184/update-inside-a-function-only-searches-the-global-environment]. Bạn thường có thể tìm ra những cạm bẫy này bằng cách cố gắng sử dụng 'data.table' - xem [http://stackoverflow.com/questions/15096811/why-is-using-update-on-a-lm-inside-a- grouped-data-table-loss-its-model-data/15376891 # 15376891] – mnel

+3

Tác phẩm này: 'do.call (" lm ", danh sách (ff, quote (mtcars)))' –

+0

@ G.Gothendieck - Cảm ơn . Điều đó có vẻ tốt, và có vẻ như nó không nên đặt ra bất kỳ vấn đề xuống đường. (Ngoài ra, cảm ơn mnel cho các liên kết thú vị.) –

Trả lời

2

Tôi luôn do dự khi tuyên bố có không tình huống trong đó một cái gì đó liên quan đến môi trường R và Phạm vi có thể cắn, nhưng ... sau khi một số thăm dò hơn, sử dụng đầu tiên của tôi ở trên trông an toàn.

Nó chỉ ra rằng cuộc gọi được in có một chút cá trích đỏ.

Công thức rằng thực được sử dụng bởi các chức năng khác (và một trong những chiết xuất bởi formula()as.formula()) là một lưu trữ trong các yếu tố terms của đối tượng phù hợp, và được quyền công thức thực tế. (Yếu tố terms chứa một đối tượng của lớp "terms", mà chỉ là một "formula" với một loạt các thuộc tính kèm theo.)

Để thấy rằng tất cả các đề xuất trong câu hỏi của tôi và những ý kiến ​​liên quan lưu trữ cùng một đối tượng "formula" (lên đến môi trường liên quan), hãy chạy như sau.

## First the three approaches in my post 
formula(fun(XX=c("cyl", "disp"))) 
# mpg ~ cyl + disp 
# <environment: 0x026d2b7c> 

formula(lm(mpg ~ cyl + disp, data=mtcars)) 
# mpg ~ cyl + disp 

formula(fun2(XX=c("cyl", "disp"))$call) 
# mpg ~ cyl + disp 
# <environment: 0x02c4ce2c> 

## Then Gabor Grothendieck's idea 
XX = c("cyl", "disp") 
ff <- reformulate(response="mpg", termlabels=XX) 
formula(do.call("lm", list(ff, quote(mtcars)))) 
## mpg ~ cyl + disp 

Để xác nhận rằng formula() thực sự được bắt nguồn sản lượng của nó từ các yếu tố terms của đối tượng phù hợp, có một cái nhìn tại stats:::formula.lmstats:::formula.terms.

+0

Khám phá thú vị. Tôi đã sử dụng phương thức 'do.call' trước đây vì một số câu hỏi tương tự. Thật tuyệt khi biết các chức năng này không phụ thuộc vào công thức/cuộc gọi được lưu trữ. Tuy nhiên, tôi tin rằng 'cập nhật' hiện, vì vậy hãy chú ý đến việc sử dụng đó. – Aaron

+0

@Aaron - Cảm ơn. Bạn đang đề cập đến vấn đề tương tự như mnel đã làm trong bình luận đầu tiên sau câu hỏi của tôi? Nếu vậy, tôi có đúng khi hiểu rằng lỗ hổng đó sẽ áp dụng như nhau cho * bất kỳ * nào của các cuộc gọi ở trên không? (tức là sử dụng 'do.call()' để khởi động cuộc gọi đến 'lm()' không giúp bạn tránh các vấn đề phạm vi 'update()', phải không?) –

+1

Sau khi khám phá thêm, có vẻ như 'update' là cũng an toàn. Tôi chắc chắn nó không phải là mặc dù, nhưng có lẽ tôi đã sai tất cả thời gian này. Tuy nhiên, có những chức năng phụ thuộc vào chức năng là chính xác, ví dụ, 'anova.lme'; xem http://stackoverflow.com/q/7666807/210673. – Aaron

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