-
Notifications
You must be signed in to change notification settings - Fork 14
Description
solve() will sometimes produce an undesirable result when the matrix is singular but the determinant is extremely close but not equal to 0.
> a <- cov(model.matrix(~ as.factor(gear) + 0, data = mtcars))
> a[1] <- a[1] + 1e-10
> det(a)
[1] 2.926638e-12
> det(a) == 0
[1] FALSE
> all.equal(det(a), 0)
[1] TRUE
> solve(a)
as.factor(gear)3 as.factor(gear)4 as.factor(gear)5
as.factor(gear)3 1e+10 1e+10 1e+10
as.factor(gear)4 1e+10 1e+10 1e+10
as.factor(gear)5 1e+10 1e+10 1e+10Our generalized inverse code produces a more sensible inverse:
> s <- svd(a)
> nz <- (s$d > sqrt(.Machine$double.eps) * s$d[1])
> s$v[, nz] %*% (t(s$u[, nz])/s$d[nz])
[,1] [,2] [,3]
[1,] 1.8944444 -0.3444444 -1.550000
[2,] -0.3444444 2.0666667 -1.722222
[3,] -1.5500000 -1.7222222 3.272222This is related to #230 in the sense that the issue in 230 arose when an externally calculated distance matrix had extreme values due to this bug, however this is a separate concern as this happens internally.
Fix is to drop down to generalized inverse if either solve() errors OR the determinant is "close" to 0. I have a rough solution coded up but don't really have time right now to finish testing and polishing.
How to determine close to 0? .Machine$double.eps is 2e-16 on my macs, but that feels too small. MatchIt will be using 1e-8 for their threshold in their Mahalanobis calculation. I'm tempted to go even higher like 1e4 (adjusting the nz calculation as well) - is there a big downside to carrying out the generalized inverse in situations like this?