-2

I am not sure what I am doing wrong here.

ee <- eigen(crossprod(X))$values
for(i in 1:length(ee)){
if(ee[i]==0:1e^-9) stop("singular Matrix")}

Using the eigen value approach, I am trying to determine if the matrix is singular or not. I am attempting to find out if one of the eigen values of the matrix is between 0 and 10^-9. How can I use the if statement (as above) correctly to achieve my goal? Is there any other way to approach this?

what if I want to concatenate the zero eigen value in vector

zer <-NULL
ee <- eigen(crossprod(X))$values 
for(i in 1:length(ee)){ 
if(abs(ee[i])<=1e-9)zer <- c(zer,ee[i])} 

Can I do that?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Falcon-StatGuy
  • 347
  • 2
  • 6
  • 15
  • 1
    What exactly are you trying to convey in the condition of your if statement? – Dason Sep 12 '12 at 01:15
  • 4
    You've already asked a few questions, yet you have not voted a single answer up, nor accepted one. Please consider doing so (http://stackoverflow.com/faq#howtoask). – flodel Sep 12 '12 at 01:24
  • @flodel I am new to the site and still getting the hang of things. thank you for the advice – Falcon-StatGuy Sep 12 '12 at 01:41
  • There is no need for the for loop for either part, see my solution. – mnel Sep 12 '12 at 02:40

3 Answers3

3

@AriBFriedman is quite correct. I can, however see a couple of other issues

  • 1e^-9 should be 1e-9.
  • 0:1e-9 returns 0, (: creates a sequence by one between 0 and 1e-9, therefore returns just 0. See ?`:` for more details
  • Using == with decimals will cause problems due to floating point arithmetic

In the form written, your code checks (individually) whether the elements ee[i] == 0, which is not what you want (nor does it make sense in terms floating point arithmetic)

You are looking for cases where the eigen value is less than this small number, so use less than (<).

What you are looking for is something like

if(any(abs(ee) < 1e-9))  stop('singular matrix')

If you want to get the 0 (or small) eigen vectors, then use which

# this will give the indexs (which elements are small)
small_values <- which(abs(ee) < 1e-9))
# and those small values
ee[small_values]

There is no need for the for loop as everything being done is vectorized.

mnel
  • 113,303
  • 27
  • 265
  • 254
  • you are right 0:1e-9 will return zero and I was awware of 1e^-9 I just wrote like this to identify that this is a small number. – Falcon-StatGuy Sep 12 '12 at 01:26
  • 1
    If you post code that does not work and ask to fix it, there is no point in putting in *known* syntax errors! – mnel Sep 12 '12 at 01:31
2

if takes a single argument of length 1.

Try either ifelse or using any() or all() to turn your vector of logicals into a logical vector of length 1.

Ari B. Friedman
  • 71,271
  • 35
  • 175
  • 235
1

Here's an example reproducing your data:

X <- matrix(1:10,1:10)
ee <- eigen(crossprod(X))$values

This will test if any of the values of ee are > 0 AND< 1e-9

if (any((ee > 0) & (ee < 1e-9))) {stop("singular matrix")}
thelatemail
  • 91,185
  • 12
  • 128
  • 188