快速替代R car::预测子集平方和交叉积矩阵计算的方差分析
我需要计算多元线性模型中的平方和叉积矩阵(实际上是这个矩阵的轨迹),Y(nxq)和x(nxp)。执行此操作的标准R代码为:快速替代R car::预测子集平方和交叉积矩阵计算的方差分析,r,performance,matrix,lm,manova,R,Performance,Matrix,Lm,Manova,我需要计算多元线性模型中的平方和叉积矩阵(实际上是这个矩阵的轨迹),Y(nxq)和x(nxp)。执行此操作的标准R代码为: require(MASS) require(car) # Example data q <- 10 n <- 1000 p <- 10 Y <- mvrnorm(n, mu = rep(0, q), Sigma = diag(q)) X <- as.data.frame(mvrnorm(n, mu = rnorm(p), Sigma =
require(MASS)
require(car)
# Example data
q <- 10
n <- 1000
p <- 10
Y <- mvrnorm(n, mu = rep(0, q), Sigma = diag(q))
X <- as.data.frame(mvrnorm(n, mu = rnorm(p), Sigma = diag(p)))
# Fit lm
fit <- lm( Y ~ ., data = X )
# Type I sums of squares
summary(manova(fit))$SS
# Type III sums of squares
type = 3 # could be also 2 (II)
car::Anova(fit, type = type)$SSP
car
对于大型n:
我已经尝试了Rcpp
实现,取得了很大的成功,因为R中的这些矩阵产品已经使用了非常高效的代码
有没有关于如何更快地完成这项工作的提示
更新
在阅读了答案之后,我尝试了本文提出的解决方案,该解决方案依赖于QR/SVD/Cholesky分解来计算hat矩阵。然而,似乎car::Anova
计算所有p=30矩阵的速度比我只计算一个(s=1)还要快!!例如,n=5000,q=10:
Unit: milliseconds
expr min lq mean median uq max neval
ME 1137.5692 1202.9888 1257.8979 1251.6834 1318.9282 1398.9343 10
QR 1005.9082 1031.9911 1084.5594 1037.5659 1095.7449 1364.9508 10
SVD 1026.8815 1065.4629 1152.6631 1087.9585 1241.4977 1446.8318 10
Chol 969.9089 1056.3093 1115.9608 1102.1169 1210.7782 1267.1274 10
CAR 205.1665 211.8523 218.6195 214.6761 222.0973 242.4617 10
更新2
目前最好的解决方案是检查car::Anova
(即函数car::Anova.III.mlm
,然后检查car::linearHypothesis.mlm
)并重新实现它们,以考虑预测因子的子集,而不是所有预测因子
car
的相关代码如下(我跳过了检查,简化了一点):
B这一行和它下面的类似的H1
行可能会得到改进:
H <- tcrossprod(tcrossprod(X, solve(crossprod(X))), X)
H这一行和它下面的类似的H1
行可能会得到改进:
H <- tcrossprod(tcrossprod(X, solve(crossprod(X))), X)
H谢谢!我通过QR/SVD/Cholesky更新了问题,以包括结果,但是,car似乎仍然很快。您应该显示更多代码,因此我们有一个可复制的示例。我添加了一些示例数据,它可能只是多变量正常值。目前,我找到的最佳解决方案是通过我感兴趣的car
重新实现代码,但只使用术语的子集。这是目前为止最快的。按照我在循环的最后一行中的答案中的建议,您可以获得另一个小的改进(大约7%)。我不确定这通常是正确的还是仅在示例中,但是L%*%V%*%t(L)
是一个标量,因此您可以通过将最后一行替换为crossprod(L%*%B)来获得另外7%/as.numeric(L%*%V%*%t(L))
。谢谢!我通过QR/SVD/Cholesky更新了问题,以包括结果,但是,car似乎仍然很快。您应该显示更多代码,因此我们有一个可复制的示例。我添加了一些示例数据,它可能只是多变量正常值。目前,我找到的最佳解决方案是通过我感兴趣的car
重新实现代码,但只使用术语的子集。这是目前为止最快的。按照我在循环的最后一行中的答案中的建议,您可以获得另一个小的改进(大约7%)。我不确定这通常是正确的还是仅在示例中,但是L%*%V%*%t(L)
是一个标量,因此您可以通过将最后一行替换为crossprod(L%*%B)来获得另外7%/as.numeric(L%*%V%*%t(L))
。
H <- tcrossprod(tcrossprod(X, solve(crossprod(X))), X)