Georges Dupret
Georges Dupret

Reputation: 89

efficiently update matrix element with a matrix of indices

I have a matrix of indices I where some of the indices are repeated. I put an example below.

I have another matrix A with dimensions compatible with the indices and initiated to 0 everywhere. I would like to do something like

A[I] += 1

I face two issues:

  1. A[I] = A[I] + 1 is too inefficient
  2. matrix I has redundant indices. For example rows 2 & 6 are identical and I would like to obtain A[1,2] = 2

A partial answer would be to create a 3 columns matrix with the two first columns being the product of unique(I) and the third column with the counts, but I don't see any solution for that either. Any pointer or help would be greatly appreciated!

> I is:
     [,1] [,2]
[1,]    1    1
[2,]    1    2
[3,]    1    3
[4,]    1    4
[5,]    1    1
[6,]    1    2
[7,]    1    3

Upvotes: 3

Views: 4085

Answers (2)

Greg Snow
Greg Snow

Reputation: 49640

This may be quickest using sparse matrix methods (see the Matrix package and others).

Using standard matricies you could collapse the identical rows using the xtabs function then matrix assignment (edited based on comment):

I <- cbind(1, c(1:4,1:3))

tmp <- as.data.frame(xtabs( ~I[,1]+I[,2] ))

A <- matrix(0, nrow=5, ncol=5)
tmp2 <- as.matrix(tmp[,1:2])
tmp3 <- as.numeric(tmp2)
dim(tmp3) <- dim(tmp2)
A[ tmp3 ] <- tmp[,3]
A

You could probably make it a little quicker by pulling the core functionality out of as.data.frame.table rather than converting to data frame and back again.

Here is another version that may be more efficient. It will overwrite some 0's with other 0's computed by xtabs:

I <- cbind(1:5,1:5)
A <- matrix(0, 5, 5)

tmp <- xtabs( ~I[,2]+I[,1] )

A[ as.numeric(rownames(tmp)), as.numeric(colnames(tmp)) ] <- c(tmp)
A

If the A matrix has dimnames and the I matrix has the names instead of the indexes, then this later one will also work (just remove the as.numerics.

Upvotes: 3

Josh O&#39;Brien
Josh O&#39;Brien

Reputation: 162321

Here you go:

## Reproducible versions of your A and I objects
A <- matrix(0, nrow=2, ncol=5)
## For computations that follow, you'll be better off having this as a data.frame
## (Just use `I <- as.data.frame(I)` to convert a matrix object I).
I <- read.table(text=" 1    1
1    2
1    3
1    4
1    1
1    2
1    3", header=FALSE)

## Create data.frame with number of times each matrix element should
## be incremented
I$count <- ave(I[,1], I[,1], I[,2], FUN=length)
I <- unique(I)

## Replace desired elements, using a two column matrix (the "third form of
## indexing" mentioned in "Matrices and arrays" section" of ?"[").
A[as.matrix(I[1:2])] <- I[[3]]

A
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    2    2    2    1    0
# [2,]    0    0    0    0    0

Upvotes: 2

Related Questions