我有一个函数执行Box的M检验,以确定协方差的相等性 多元线性模型中的矩阵。我想把它变成一个带有公式方法的S3泛型函数,这是最自然的界面。
完整的当前代码位于https://gist.github.com/friendly/749b5a69a067e02b87dd。我可以将它全部粘贴在这里,但也许是那个链接 已经足够了。
我不了解访问模型对象组件的函数中使用的很多魔法。我将leveneTest
包中car
中找到的代码用作模板,解决了单变量模型的类似问题。
以下是使用默认方法boxM.default
的快速测试:
data(iris)
res <- boxM(iris[, 1:4], iris[, "Species"])
res
给出了期望的结果:
> data(iris)
> res <- boxM(iris[, 1:4], iris[, "Species"])
> res
Box's M-test for Homogeneity of Covariance Matrices
data: iris[, 1:4]
Chi-Sq (approx.) = 140.94, df = 20, p-value < 2.2e-16
>
当我尝试直接调用公式方法boxM.formula
时,它也可以工作,提供与上面相同的输出。
boxM( cbind(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width) ~ Species, data=iris)
但是,boxM.lm
方法的此测试失败:
> iris.mod <- lm(cbind(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width) ~ Species, data=iris)
> boxM(iris.mod)
Error in cbind(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width) :
object 'Sepal.Length' not found
> traceback()
8: cbind(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width)
7: eval(expr, envir, enclos)
6: eval(predvars, data, env)
5: model.frame.default(form, data)
4: model.frame(form, data) at boxM.R#59
3: boxM.formula(formula(y), data = model.frame(y), ...) at boxM.R#76
2: boxM.lm(iris.mod) at boxM.R#2
1: boxM(iris.mod)
>
我想我明白为什么它会失败 - 与查找model.frame()
中的变量的环境有关,而不是如何纠正它。
有人可以帮忙吗?
答案 0 :(得分:1)
您设计的boxM
函数可以将lm
对象作为输入。实现尝试从lm
中提取公式和model.frame,并将其重用于boxM.formula
。
似乎无法解决问题的原因是因为model.frame(iris.mod)
没有返回原始data.frame
而是返回2列data.frame,其中第1列包含左侧矩阵变量,第二个是右侧的矢量。您可以通过
class(model.frame(iris.mod))
dim(model.frame(iris.mod))
names(model.frame(iris.mod))
model.frame(iris.mod)[,1]
model.frame(iris.mod)[,2]
由于model.frame(iris.mod)
已将数据解析为可计算格式,因此当boxM.default
对象为输入时,您可以应用boxM.formula
而不是lm
。例如,这似乎有效:
boxM.default(Y = model.frame(iris.mod)[,1],
group = model.frame(iris.mod)[,2])
# Box's M-test for Homogeneity of Covariance Matrices
#data: model.frame(iris.mod)[, 1]
#Chi-Sq (approx.) = 140.94, df = 20, p-value < 2.2e-16
答案 1 :(得分:0)
我解决这个问题的同事说:“你被非标准评估所困扰。”
这是一个有效的解决方案,更通常与模型对象的S3方法一致。它在环境中找到data
模型公式。
boxM.lm <- function(y, ...) {
data <- getCall(y)$data
y <- if (!is.null(data)) {
data <- eval(data, envir = environment(formula(y)))
update(y, formula(y), data = data)
}
else update(y, formula(y))
boxM.formula(formula(y), data=eval(data, envir = environment(formula(y))), ...)
}