achimneyswallow achimneyswallow - 1 month ago 6
R Question

avoid for loops in a large matrix in R

I have a very large matrix that requires some computation. As a for loop is notoriously slow in R, I would like to replace it with some smarter function, such as apply. However, I am scratching my head without being able to do it.

Here is the for loop that I wrote with a small example matrix.

d <- matrix(c(1,1,0,0,1,1,1,0,0), 3,3)
for (i in 1:nrow(d)) {
for (j in 1:ncol(d)) {
if (d[i,j] == 1) {
d[j, i] =1
} else {d[j,i] = 0}
}
}


This code nicely replaces values as wish, yielding a symmetric matrix in which d[i,j] = d[j,i]. However, it can take lots of time and memory when the matrix is big. What would be an efficient alternative way to get it done? Thank you!!

Answer

How about this

d[lower.tri(d)] <- (t(d)[lower.tri(d)] == 1)

This gives you a symmetric matrix. Note that I'm taking the lower triangle of the transpose instead. You want to read the upper triangle row wise but d[upper.tri(d)] will return the column wise values. On the other hand, taking the lower triangle of the transpose is equivalent to reading the upper triangle row wise.

With the example you provided, taking the upper triangle work just fine because both d[upper.tri(d)] and t(d)[lower.tri(d)] will return 0 1 0. So here is a comparison with a larger matrix:

d <- matrix(c(1,1,0,1,0,1,0,0,0, 1,0,1,0,1,0,1), 4,4)

This case, d[upper.tri(d)] will return 0 0 1 0 1 0 whereas t(d)[lower.tri(d)] will return 0 0 0 1 1 0.

Comparison:

d2 <- d
d2[lower.tri(d2)] <- (t(d2)[lower.tri(d2)] == 1)

for (i in 1:nrow(d)) {
    for (j in 1:ncol(d)) {
        if (d[i,j] == 1) {
            d[j, i] =1
        } else {d[j,i] = 0}
    }
}

all.equal(d2, d)
## TRUE
Comments