我有一个矩阵
[,1] [,2]
[1,] 1 3
[2,] 4 6
[3,] 11 12
[4,] 13 14
我想把这个矩阵转换成这样的向量:
# indices 1-6, 11-14 = 1, gap indices 7-10 = 0
xx <- c(1,1,1,1,1,1,0,0,0,0,1,1,1,1)
思想:矩阵的值从1到14。向量的长度也是14。如果假设第一列是起始,第二列是结束,那么对于矩阵中的那些范围,即1-3,4-6,11-12,13-4 (或等效于1-6,11-14),我希望这些指数的值在我的输出向量中是1。在我的输出向量中,在指数7-10处,矩阵中的7-10的间隙应该是0。(谢谢编辑)
然而,有时矩阵不给出矩阵中的最后一个值。但是,我总是知道转换后的大小,比方说,在这个例子中是20。那么,结果向量应该是这样的:
# indices 1-6, 11-14 = 1, gap indices 7-10 = 0, indices 15-20 = 0
xx <- c(1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0)
没有循环我怎么能做到这一点?我的矩阵很长,我试着用循环很慢。
发布于 2013-06-15 07:47:43
下面是使用IRanges
包的一个答案:
require(IRanges)
xx.ir <- IRanges(start = xx[,1], end = xx[,2])
as.vector(coverage(xx.ir))
# [1] 1 1 1 1 1 1 0 0 0 0 1 1 1 1
如果指定整个向量长度的min
和max
值,则:
max.val <- 20
min.val <- 1
c(rep(0, min.val-1), as.vector(coverage(xx.ir)), rep(0, max.val-max(xx)))
发布于 2013-06-15 07:24:37
@Arun的回答似乎更好。
既然我理解了这个问题(或者说我明白了?)这是基R中的一个解决方案,它利用了只需要保持连续的零序列的思想。
find.ones <- function (mat) {
ones <- rep(0, max(mat))
ones[c(mat)] <- 1
ones <- paste0(ones, collapse="")
ones <- gsub("101", "111", ones)
ones <- as.numeric(strsplit(ones, "")[[1]])
ones
}
在OP的原始示例中:
m <- matrix(c(1, 3, 4, 6, 11, 12, 13, 14), ncol=2, byrow=TRUE)
find.ones(m)
[1] 1 1 1 1 1 1 0 0 0 0 1 1 1 1
为了对解决方案进行基准测试,让我们把矩阵做得足够大:
set.seed(10)
m <- sample.int(n=1e6, size=5e5)
m <- matrix(sort(m), ncol=2, byrow=TRUE)
head(m)
[,1] [,2]
[1,] 1 3
[2,] 4 5
[3,] 9 10
[4,] 11 13
[5,] 14 18
[6,] 22 23
system.time(ones <- find.ones(m))
user system elapsed
1.167 0.000 1.167
发布于 2013-06-15 11:49:59
在这里抛出这个循环时,它使用的是基R,并且由于不可避免的循环是由rep
处理的,所以它应该有点快
zero.lengths <- m[,1] - c(0, head(m[,2], -1)) - 1
one.lengths <- m[,2] - m[,1] + 1
rep(rep(c(0, 1), nrow(m)),
as.vector(rbind(zero.lengths, one.lengths)))
或使用sequence
的另一种解决方案
out <- integer(m[length(m)]) # or `integer(20)` following OP's edit.
one.starts <- m[,1]
one.lengths <- m[,2] - m[,1] + 1
one.idx <- sequence(one.lengths) + rep(one.starts, one.lengths) - 1L
out[one.idx] <- 1L
https://stackoverflow.com/questions/17121205
复制相似问题