2012-09-20 59 views
4

我有一个矩阵,我想在其中将某些特定元素归零。在R中访问一定范围的矩阵元素

举例来说,假设我的矩阵是:

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) 

哪些元素所以,例如我会继续元件3:6行1,并将元素1:2和7:10设置为0. 对于第2行,我将保留6:8并将剩下的零置为零,依此类推。现在

,我可以很容易做到:

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

其给出正确的结果。

然而,在我的具体情况下,我正在使用一个~15000 x 3000的矩阵,这使得使用这种循环的时间非常长。

如何加快此代码?我虽然使用apply,但我如何访问m.from和m.to的正确索引?

+0

我没有想到它通过完全,但我不知道一个快速的解决方案可能是通过附加'm.from'和'm.to'作为矩阵的附加列。然后,一个“应用”解决方案将是微不足道的,你甚至可以矢量化它。 – joran

回答

8

这里有一个简单的矩阵解决方案为导向:

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 

(我想我可能会赢得这一个将R高尔夫奖金了。)我的哪些条目将是:

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

双柏忌!尝试'z = col(m); m [z <=m.from|z> = m.to] = 0'。我鼓励R爱好者试试这个:http://codegolf.stackexchange.com/questions。 R有可能做出简短的回答,但并不总是被投票通过。 – flodel

+0

关于代码高尔夫的笑话,你对问题的回答非常优雅。你有我的投票。 – flodel

+0

你可以这样做吗?哇,我并不期待所有这些变体。 – nico

4

最好的解决方案是预先计算所有要被替换的索引,然后用一个赋值操作替换它们。

由于R在column-major order中存储矩阵,我发现在矩阵的转置版本中考虑要替换的元素序列更容易。这就是我在下面使用的。然而,如果对t()的两次调用过于昂贵,我相信你可以找出一个巧妙的方式来计算未转置矩阵的索引 - 也许使用包含行和列索引的两列矩阵。

## 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's 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 
+0

这看起来确实非常有趣...我会尝试它,我会让你知道! – nico

+0

美丽!即使使用大矩阵,速度也非常快! – nico

2

A sapply版本。

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 

经过时间尚未

+0

不错!这比其他解决方案还要快。 – nico

+0

非常有趣。很高兴知道sapply对于这类事情是非常优化的。 –

+0

@ JoshO'Brien:我想在以前的解决方案中,问题是你有'm',它的转置和'ii'以及一个占用大量内存的大矩阵。 – nico

1

测试此选项构造来代替的两列矩阵的标定元件,并且不需要矩阵换位,所以应该是很难被击败,speedwise

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