Access to a specific range of matrix elements in R

I have a matrix in which I want to reset some specific elements.

For example, imagine my matrix:

m <- matrix(1:100, ncol=10) 

Then I have two vectors indicating which items to keep

 m.from <- c(2, 5, 4, 4, 6, 3, 1, 4, 2, 5) m.to <- c(7, 9, 6, 8, 9, 5, 6, 8, 4, 8) 

So, for example, I will store the 3: 6 elements in line 1 and set the elements 1: 2 and 7:10 to 0. For line 2, I will save 6: 8 and the rest zero, etc.

Now I could easily do:

 for (line in 1:nrow(m)) { m[line, 1:m.from[line]] <- 0 m[line, m.to[line]:ncol(m)] <- 0 } 

which gives the correct result.

In my specific case, however, I am working on a ~ 15000 x 3000 matrix, which makes using this type of loop painfully long.

How can I speed up this code? I use apply , but how do I access the correct m.from and m.to index?

+4
source share
4 answers

Here's a simple matrix-oriented solution:

 m[col(m) <= m.from] <- 0 m[col(m) >= m.to] <- 0 m [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [1,] 0 0 21 31 41 51 0 0 0 0 [2,] 0 0 0 0 0 52 62 72 0 0 [3,] 0 0 0 0 43 0 0 0 0 0 [4,] 0 0 0 0 44 54 64 0 0 0 [5,] 0 0 0 0 0 0 65 75 0 0 [6,] 0 0 0 36 0 0 0 0 0 0 [7,] 0 17 27 37 47 0 0 0 0 0 [8,] 0 0 0 0 48 58 68 0 0 0 [9,] 0 0 29 0 0 0 0 0 0 0 [10,] 0 0 0 0 0 60 70 0 0 0 

(I think I could win an R Golf prize on this, too.) Why would I write:

 m[col(m)<=m.from|col(m)>= m.to]<-0 
+8
source

The best solution would be one that pre-computes all the indices to be replaced and then replaces them with a single assignment operation.

Since R stores matrices in column order, it's easier for me to think about sequences of elements that need to be replaced in the transposed version of your matrix. This is what I used below. If, however, two t() calls are too expensive, I'm sure you can find a smart way to calculate the indices of an untranslated matrix — perhaps using a two-column matrix containing row and column indices.

 ## Your example m <- matrix(1:100, ncol=10) m.from <- c(2, 5, 4, 4, 6, 3, 1, 4, 2, 5) m.to <- c(7, 9, 6, 8, 9, 5, 6, 8, 4, 8) ## Let work with a transposed version of your matrix tm <- t(m) ## Calculate indices of cells to be replaced i <- (seq_len(ncol(tm)) - 1) * nrow(tm) m.to <- c(1, m.to + i) m.from <- c(m.from + i, length(m)) ii <- unlist(mapply(seq, from = m.to, to = m.from)) ## Perform replacement and transpose back results tm[ii] <- 0 m <- t(tm) # [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] # [1,] 0 0 21 31 41 51 0 0 0 0 # [2,] 0 0 0 0 0 52 62 72 0 0 # [3,] 0 0 0 0 43 0 0 0 0 0 # [4,] 0 0 0 0 44 54 64 0 0 0 # [5,] 0 0 0 0 0 0 65 75 0 0 # [6,] 0 0 0 36 0 0 0 0 0 0 # [7,] 0 17 27 37 47 0 0 0 0 0 # [8,] 0 0 0 0 48 58 68 0 0 0 # [9,] 0 0 29 0 0 0 0 0 0 0 # [10,] 0 0 0 0 0 60 70 0 0 0 
+4
source

A sapply version.

 m <- matrix(1:100, ncol=10) m.from <- c(2, 5, 4, 4, 6, 3, 1, 4, 2, 5) m.to <- c(7, 9, 6, 8, 9, 5, 6, 8, 4, 8) t(sapply(1:nrow(m), function(i) replace(m[i,], c(1:m.from[i], m.to[i]:ncol(m)), 0 ))) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [1,] 0 0 21 31 41 51 0 0 0 0 [2,] 0 0 0 0 0 52 62 72 0 0 [3,] 0 0 0 0 43 0 0 0 0 0 [4,] 0 0 0 0 44 54 64 0 0 0 [5,] 0 0 0 0 0 0 65 75 0 0 [6,] 0 0 0 36 0 0 0 0 0 0 [7,] 0 17 27 37 47 0 0 0 0 0 [8,] 0 0 0 0 48 58 68 0 0 0 [9,] 0 0 29 0 0 0 0 0 0 0 [10,] 0 0 0 0 0 60 70 0 0 0 

Elapsed time not yet verified

+2
source

This parameter creates replaceable indexing elements of a matrix with two columns and does not require matrix transpositions, therefore they should be beaten, accelerated

 ## Your data m <- matrix(1:100, ncol=10) m.from <- c(2, 5, 4, 4, 6, 3, 1, 4, 2, 5) m.to <- c(7, 9, 6, 8, 9, 5, 6, 8, 4, 8) ## Construct a two column matrix with row (ii) and column (jj) indices ## of cells to be replaced ii <- rep.int(1:ncol(m), times = (m.from + (ncol(m) - m.to + 1))) jj <- mapply(seq, from = m.from + 1, to = m.to - 1) jj <- unlist(sapply(jj, function(X) setdiff(1:10,X))) ij <- cbind(ii, jj) ## Replace cells m[ij] <- 0 # [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] # [1,] 0 0 21 31 41 51 0 0 0 0 # [2,] 0 0 0 0 0 52 62 72 0 0 # [3,] 0 0 0 0 43 0 0 0 0 0 # [4,] 0 0 0 0 44 54 64 0 0 0 # [5,] 0 0 0 0 0 0 65 75 0 0 # [6,] 0 0 0 36 0 0 0 0 0 0 # [7,] 0 17 27 37 47 0 0 0 0 0 # [8,] 0 0 0 0 48 58 68 0 0 0 # [9,] 0 0 29 0 0 0 0 0 0 0 # [10,] 0 0 0 0 0 60 70 0 0 0 
+1
source

Source: https://habr.com/ru/post/1435320/


All Articles