yearntolearn
yearntolearn

Reputation: 1074

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.

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!!

Upvotes: 0

Views: 322

Answers (1)

parksw3
parksw3

Reputation: 659

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

Upvotes: 5

Related Questions