pat
pat

Reputation: 627

how to populate matrix of indices with vector of values

I have a matrix (m.idx) containing position elements of a vector I want to index.

> m.idx
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    2    3    4    5
[2,]    3    4    5    6    7
[3,]    5    6    7    8    9

Suppose x is my vector.

x <- c(9,3,2,5,3,2,4,8,9)

I want to repopulate the matrix index with the corresponding position elements of x.

so I would have...

> m.pop
     [,1] [,2] [,3] [,4] [,5]
[1,]    9    3    2    5    3
[2,]    2    5    3    2    4
[3,]    3    2    4    8    9

I can kind of do it in a kludgy way with the following.

> m.pop <- t(matrix(t(matrix(x[c(t(m.idx))])),ncol(m.idx),nrow(m.idx)))

> m.pop
     [,1] [,2] [,3] [,4] [,5]
[1,]    9    3    2    5    3
[2,]    2    5    3    2    4
[3,]    3    2    4    8    9

But it seems like there may be an easier method to index the values. What is the best (and fastest/efficient for large sets) way to do this?

Upvotes: 4

Views: 1076

Answers (3)

Rich Scriven
Rich Scriven

Reputation: 99331

How about:

m.idx[] <- x[m.idx]
m.idx
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    9    3    2    5    3
# [2,]    2    5    3    2    4
# [3,]    3    2    4    8    9

Or if you don't want to overwrite the m.idx matrix, you can do this instead:

m.pop <- m.idx
m.pop[] <- x[m.pop]

Added:

One other method, using structure, is also quite fast:

structure(x[m.idx], .Dim = dim(m.idx))
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    9    3    2    5    3
# [2,]    2    5    3    2    4
# [3,]    3    2    4    8    9

When applied to the large m.idx matrix in Ananda Mahto's answer, the timings on my machine are

fun5 <- function() structure(x[m.idx], .Dim = dim(m.idx))
microbenchmark(fun1(), fun2(), fun3(), fun4(), fun5(), times = 10)
# Unit: milliseconds
#    expr       min        lq    median        uq       max neval
#  fun1()  303.3473  307.2064  309.2275  352.5076  353.6911    10
#  fun2()  548.0928  555.3363  587.6144  593.4492  596.5611    10
#  fun3()  480.6181  487.5807  507.5960  529.9696  533.0403    10
#  fun4() 1222.6718 1231.3384 1259.8395 1269.6629 1292.2309    10
#  fun5()  401.8450  403.7216  432.7162  455.4638  487.1755    10
identical(fun1(), fun5())
# [1] TRUE

You can see that structure is actually not too bad in terms of speed.

Upvotes: 5

A5C1D2H2I1M1N2O1R2T1
A5C1D2H2I1M1N2O1R2T1

Reputation: 193517

Maybe you can just use dim after matching the vector/matrix:

`dim<-`(x[m.idx], dim(m.idx))
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    9    3    2    5    3
# [2,]    2    5    3    2    4
# [3,]    3    2    4    8    9

The x[m.idx] gets you the values you're interested in:

> x[m.idx]
 [1] 9 2 3 3 5 2 2 3 4 5 2 8 3 4 9

And, since this should be returned int he same dimensions at the original, you just reassign the same dim to it.


For fun, some timings:

fun1 <- function() `dim<-`(x[m.idx], dim(m.idx))
fun2 <- function() { m.idx[] <- x[m.idx]; m.idx }
fun3 <- function() matrix(x[m.idx], ncol = ncol(m.idx))
fun4 <- function() t(matrix(t(matrix(x[c(t(m.idx))])),ncol(m.idx),nrow(m.idx)))

m.idx <- matrix(c(1, 2, 3, 4, 5, 
                  3, 4, 5, 6, 7, 
                  5, 6, 7, 8, 9), 
                nrow = 3, byrow = TRUE)
x <- c(9, 3, 2, 5, 3, 2, 4, 8, 9)

set.seed(1)
nrow = 10000  ## Adjust nrow and ncol to test different sizes
ncol = 1000
m.idx <- matrix(sample(unique(m.idx), nrow*ncol, TRUE), ncol = ncol)
library(microbenchmark)

microbenchmark(fun1(), fun2(), fun3(), fun4(), times = 10)
# Unit: milliseconds
#    expr       min        lq    median        uq       max neval
#  fun1()  388.7123  403.3614  419.5792  475.7645  553.3420    10
#  fun2()  800.5524  838.2398  872.8189  912.1007  978.1500    10
#  fun3()  694.1511  720.5165  737.9900  799.5069  876.2552    10
#  fun4() 1941.1999 2022.6578 2095.1537 2175.4864 2341.3900    10

Upvotes: 4

DatamineR
DatamineR

Reputation: 9618

matrix(x[m.idx],ncol=5)

     [,1] [,2] [,3] [,4] [,5]
[1,]    9    3    2    5    3
[2,]    2    5    3    2    4
[3,]    3    2    4    8    9

Upvotes: 5

Related Questions