R boxcox不工作

时间:2017-12-07 03:56:33

标签: r object types closures

data1 <- read.csv("~/Desktop/Group_22.csv")

View(data1)

E_var <- regmatches(names(data1), regexpr("(E[0-9])+", names(data1)))  
G_var <- regmatches(names(data1), regexpr("(G[0-9]*)+", names(data1))) 

(E_vs_G  <- paste0(c(gsub(" ", "*", outer(E_var, G_var, paste))), collapse = "+"))
(G_eff_1 <- paste("I(", G_var, ")", collapse="+"))
(G_eff_2 <- paste("I(", apply( combn(G_var, 2), 2, paste, collapse="*"), ")", collapse="+"))
(G_eff_3 <- paste("I(", apply( combn(G_var, 3), 2, paste, collapse="*"), ")", collapse="+"))
(E_eff  <- paste0("I(", E_var,"^2", ")", collapse = "+"))

(formula <- paste( "I(log(Y)) ~" , paste(c(E_eff, G_eff_1, G_eff_2, G_eff_3, E_vs_G), collapse = "+")))

M <- lm(formula, data=data1)
summary(M)

anova(M)

install.packages('MASS')

library(MASS)

boxcox(M)

Error: object of type 'closure' is not subsettable 

代码运行正常,除非它到达boxcox(M),它给了我那个错误。我做错了什么?

1 个答案:

答案 0 :(得分:1)

这是一个特别模糊且无用的错误,但如果您了解what a "closure" is,则可能会提供有关查看位置的信息。不幸的是,在这里找到它有点困难......

TL; DR

将变量从formula重命名为其他任何非函数名称的变量。例如,如果使用frm <- paste(...),则代码可以正常工作。

注意:这是一个典型的例子,说明为什么你应该避免将变量命名为与函数相同。通常,您会看到名为data的变量。在这种情况下,formula 是一个函数,由于包搜索路径,找不到您期望的顺序。

说明

要找出原因,首先我们需要调试被调用的特定函数。我们可以使用debug(boxcox)并逐步进入它,或者我们可以执行debug(MASS:::boxcox.lm)以确保我们调试正确的方法。无论如何......

boxcox(M)
# debugging in: boxcox.lm(M)
# debug: {
#     m <- length(lambda)
#     if (is.null(object$y) || is.null(object$qr)) 
#         object <- update(object, y = TRUE, qr = TRUE, ...)
#     result <- NextMethod()
#     if (plotit) 
#         invisible(result)
#     else result
# }

单步执行此操作后,调用update失败。信息量不大,我们需要介入其中。我们可以使用s进入该功能。 (顺便说一下,它使用MASS:::update.loglm,而不是导出功能。)

# Browse[2]> 
s
# debugging in: update(object, y = TRUE, qr = TRUE, ...)
# debug: UseMethod("update")
# Browse[3]> 
s
# debugging in: update.default(object, y = TRUE, qr = TRUE, ...)
# debug: {
#     if (is.null(call <- getCall(object))) 
#         stop("need an object with call component")
#     extras <- match.call(expand.dots = FALSE)$...
#     if (!missing(formula.)) 
#         call$formula <- update.formula(formula(object), formula.)
#     if (length(extras)) {
#         existing <- !is.na(match(names(extras), names(call)))
#         for (a in names(extras)[existing]) call[[a]] <- extras[[a]]
#         if (any(!existing)) {
#             call <- c(as.list(call), extras[!existing])
#             call <- as.call(call)
#         }
#     }
#     if (evaluate) 
#         eval(call, parent.frame())
#     else call
# }

单步执行此操作后,它会在最后一个命令eval(call, parent.frame())上失败。还不是很有帮助,但在查看R认为它正在使用的变量时进行故障排除很有用。例如,早些时候:

# Browse[2]> 
object
# Call:
# lm(formula = formula, data = data1)
# Coefficients:
#  (Intercept)      I(cyl^2)     I(disp^2)         I(hp)       I(drat)  I(hp * drat)           cyl  
#    3.274e+00    -2.006e-02     9.589e-06    -1.250e-02     2.388e-01     5.869e-04     4.034e-01  
#           hp          disp          drat        cyl:hp       hp:disp      cyl:drat     disp:drat  
#           NA    -9.728e-03            NA     2.122e-03    -2.418e-05    -1.155e-01     2.064e-03  

好的,这看起来很正确。接下来,意识到eval调用正试图通过对其进行更新来回忆起以前的模型。

# Browse[4]> 
call
# lm(formula = formula, data = data1)

这与我们第一次称呼它的方式类似。但是,查看实际变量,data1看起来是正确的但是......

# Browse[4]> 
formula
# function (x, ...) 
# UseMethod("formula")
# <bytecode: 0x000000001a5c20a0>
# <environment: namespace:stats>

喔。因此,最近对formula的调用中引用的lm未回复到原始调用环境,即使使用eval(...,parent.frame())也是如此。

如果您改为使用:

(frm <- paste( "I(log(Y)) ~" , paste(c(E_eff, G_eff_1, G_eff_2, G_eff_3, E_vs_G), collapse = "+")))
M <- lm(frm, data=data1)

然后事情就好了。