Reputation: 7832
I need to speed up the calculation of the inverse of a WLS covariance matrix in R, where the matrix, wls.cov.matrix
, is given by (full example below):
n = 10000
X = matrix(c(rnorm(n,1,2), sample(c(1,-1), n, replace = TRUE), rnorm(n,2,0.5)), nrow = 1000, ncol = 3)
Q = diag(rnorm(n, 1.5, 0.3))
wls.cov.matrix = solve(t(X)%*%diag(1/diag(Q))%*%X)
Is it possible to speed up this calculation?
MORE INFO VERY RELEVANT TO THE FINAL GOAL:
This is still little information, let me explain more my goal and will be clearer if there are ways to speed up my code.
I run 1,0000s of times wls.cov.matrix so I need it to be much faster.
However, each time I run it I use the same X, the only matrix that changes is Q, which is a diagonal matrix.
If X
was a square matrix, of same dim as Q
, I could just precompute X^-1
and (X^T)^(-1)
,
X.inv = solve(X)
X.inv.trans = solve(t(X))
and then for each iteration run:
Q.inv = diag(1/diag(Q))
wls.cov.matrix = X.inv%*%Q.inv%*%X.inv.trans
But my X
is not square, so is there any other trick?
Upvotes: 1
Views: 637
Reputation: 4614
The main time-consuming part here is t(X)%*%diag(1/diag(Q))%*%X
, not the calculation of its inverse.
A nice trick is to calculate it as
crossprod(X / sqrt(diag(Q)));
Confirmation:
all.equal( (t(X) %*% diag(1/diag(Q)) %*% X) , crossprod(X / sqrt(diag(Q))) );
[1] TRUE
To compare the timing run:
Qdiag = diag(Q);
system.time({(t(X) %*% diag(1/Qdiag) %*% X)})
system.time({crossprod(X / sqrt(Qdiag))})
Upvotes: 2
Reputation: 57686
Well, Q
is a diagonal matrix, so its inverse is just given by the inverses of the diagonal entries. You can thus do
X = matrix(c(rnorm(n,1,2), sample(c(1,-1), n, replace = TRUE), rnorm(n,2,0.5)), nrow = 1000, ncol = 3)
Qinv = diag(1/rnorm(n, 1.5, 0.3))
wls.cov.matrix = solve(t(X)%*%Qinv%*%X)
And in fact, this speeds things up by about a factor of 20.
Upvotes: 2