I am trying to read in a variance-covariance matrix written out by LISREL in the following format in a plain text, whitespace separated file:
0.23675E+01 0.86752E+00 0.28675E+01 -0.36190E+00 -0.36190E+00 0.25381E+01
-0.32571E+00 -0.32571E+00 0.84425E+00 0.25598E+01 -0.37680E+00 -0.37680E+00
0.53136E+00 0.47822E+00 0.21120E+01 -0.37680E+00 -0.37680E+00 0.53136E+00
0.47822E+00 0.91200E+00 0.21120E+01
This is actually a lower diagonal matrix (including diagonal):
0.23675E+01
0.86752E+00 0.28675E+01
-0.36190E+00 -0.36190E+00 0.25381E+01
-0.32571E+00 -0.32571E+00 0.84425E+00 0.25598E+01
-0.37680E+00 -0.37680E+00 0.53136E+00 0.47822E+00 0.21120E+01
-0.37680E+00 -0.37680E+00 0.53136E+00 0.47822E+00 0.91200E+00 0.21120E+01
I can read in the values correctly with scan()
or read.table(fill=T)
.
I am however not able to correctly store the read-in vector in a matrix. The following code
S <- diag(6)
S[lower.tri(S,diag=T)] <- d
fills the lower matrix by column, while it should fill it by row.
Using matrix()
does allow for the option byrow=TRUE
, but this will fill in the whole matrix, not just the lower half (with diagonal).
Is it possible to have both: only fill the lower matrix (with diagonal) and do it by row?
(separate issue I'm having: LISREL uses 'D+01' while R only recognises 'E+01' for scientific notation. Can you change this in R to accept also 'D'?)
Just read it into the upper triangular portion, rather than the lower:
S <- diag(6)
S[upper.tri(S, diag=TRUE)] <- d
t(S)
The sem
package has a very nice function, read.moments()
that is designed to do just this:
foo <- read.moments()
0.23675E+01
0.86752E+00 0.28675E+01
-0.36190E+00 -0.36190E+00 0.25381E+01
-0.32571E+00 -0.32571E+00 0.84425E+00 0.25598E+01
-0.37680E+00 -0.37680E+00 0.53136E+00 0.47822E+00 0.21120E+01
-0.37680E+00 -0.37680E+00 0.53136E+00 0.47822E+00 0.91200E+00 0.21120E+01
foo[upper.tri(foo)] <- t(foo)[upper.tri(foo)]
This gives you:
X1 X2 X3 X4 X5 X6
X1 2.36750 0.86752 -0.36190 -0.32571 -0.37680 -0.37680
X2 0.86752 2.86750 -0.36190 -0.32571 -0.37680 -0.37680
X3 -0.36190 -0.36190 2.53810 0.84425 0.53136 0.53136
X4 -0.32571 -0.32571 0.84425 2.55980 0.47822 0.47822
X5 -0.37680 -0.37680 0.53136 0.47822 2.11200 0.91200
X6 -0.37680 -0.37680 0.53136 0.47822 0.91200 2.11200
EDIT1: As for the problem with scan()
, just because it was originally printed as a lower triangle doesn't mean you have to put it in the lower triangle:) Just put it in the upper:
foo <- scan()
0.23675E+01
0.86752E+00 0.28675E+01
-0.36190E+00 -0.36190E+00 0.25381E+01
-0.32571E+00 -0.32571E+00 0.84425E+00 0.25598E+01
-0.37680E+00 -0.37680E+00 0.53136E+00 0.47822E+00 0.21120E+01
-0.37680E+00 -0.37680E+00 0.53136E+00 0.47822E+00 0.91200E+00 0.21120E+01
bar <- matrix(0,6,6)
bar[upper.tri(bar,diag=TRUE)] <- foo
bar[lower.tri(bar)] <- t(bar)[lower.tri(bar)]
EDIT2: As for the problem with D
notation, if I understand it correctly, can be fixed by first scanning characters, gsub
the D to E and coerce as numeric:
foo <- scan(what="character")
0.23675D+01
0.86752D+00 0.28675D+01
-0.36190D+00 -0.36190D+00 0.25381D+01
-0.32571D+00 -0.32571D+00 0.84425D+00 0.25598D+01
-0.37680D+00 -0.37680D+00 0.53136D+00 0.47822D+00 0.21120D+01
-0.37680D+00 -0.37680D+00 0.53136D+00 0.47822D+00 0.91200D+00 0.21120D+01
bar <- matrix(0,6,6)
bar[upper.tri(bar,diag=TRUE)] <- as.numeric(gsub("D","E",foo))
bar[lower.tri(bar)] <- t(bar)[lower.tri(bar)]
bar
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With