Skip to content

inverting singular matrixes with non-zero determinants #231

Description

@josherrickson

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+10

Our 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.272222

This 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?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions