2016-03-08 55 views
6

我有一个包含假设它的1和0的序列的载体是长度166,并且它是查找子向量0的

y <- c(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, 1,1,1,1,1,0,1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 
1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,0,0,0,1,1,1,1) 

现在我想提取从上述载体中,使得它满足两个属性

一个最长可能的子矢量

(1)子向量应当从1开始,并用总1.

(2)它可以含有至多5%的零结束子向量的长度。

我以rle函数开始。它在每个步骤计数1和0。 所以它会像

z <- rle(y) 
d <- data.frame(z$values, z$lengths) 
colnames(d) <- c("value", "length") 

它给我

> d 
    value length 
1  1  22 
2  0  1 
3  1  13 
4  0  1 
5  1  2 
6  0  1 
7  1  1 
8  0  1 
9  1  1 
10  0  5 
11  1  1 
12  0  3 
13  1  2 
14  0  1 
15  1  1 
16  0  1 
17  1  74 
18  0  2 
19  1  17 
20  0  1 
21  1  2 
22  0  1 
23  1  3 
24  0  5 
25  1  4 

在这种情况下74 + 17 2 + + 1 + 2 + 3 = 99是所需的子序列,因为它含有2+ 1 + 1 = 4个零小于99的5%。如果我们向前移动并且序列将变为99 + 5 + 4 = 108并且零将是4 + 5 = 9,这将会超过108的5%。

+0

我认为你的子向量实际上是长度为100(74 + 2 + 17 + 1 + 2 + 1 + 3)。 – josliber

回答

4

我想通过计算这个向量的运行长度编码,你非常接近。剩下的就是考虑所有的1对运行,并选择长度最长的一对,并匹配“不超过5%零”规则。

ones <- which(d$value == 1) 
# pairs holds pairs of rows in d that correspond to runs of 1's 
if (length(ones) >= 2) { 
    pairs <- rbind(t(combn(ones, 2)), cbind(ones, ones)) 
} else if (length(ones) == 1) { 
    pairs <- cbind(ones, ones) 
} 

# Taking cumulative sums of the run lengths enables vectorized computation of the lengths 
# of each run in the "pairs" matrix 
cs <- cumsum(d$length) 
pair.length <- cs[pairs[,2]] - cs[pairs[,1]] + d$length[pairs[,1]] 
cs0 <- cumsum(d$length * (d$value == 0)) 
pair.num0 <- cs0[pairs[,2]] - cs0[pairs[,1]] 

# Multiple the length of a pair by an indicator for whether it's valid and take the max 
selected <- which.max(pair.length * ((pair.num0/pair.length) <= 0.05)) 
d[pairs[selected,1]:pairs[selected,2],] 
# value length 
# 15  1  1 
# 16  0  1 
# 17  1  74 
# 18  0  2 
# 19  1  17 
# 20  0  1 
# 21  1  2 
# 22  0  1 
# 23  1  3 

实际上,我们发现子向量稍长就是一个:这可以使用combn计算所有对1和cumsum的奔跑让游程的长度从rle输出完全量化的方式进行OP发现:它有102个元素和5个0(4.90%)。

+0

谢谢josliber,它真的帮了很大忙,是的,正确的答案是102。 – Pankaj

+0

你可以用combn做同样的事情:'r = rle(y); w1 = which(r $ values == 1); (sum)(长度)*(sum(长度)[长度] v = combn(w1,2,FUN =值== 1])> .95 * sum(长度)) })); combn(w1,2)[,which.max(v)]' – Frank

+1

@Frank是的,尽管对于非常大的向量,我应该从使用向量化操作获得显着的性能提升,而不是循环遍历每对行并分别处理它们。同样'combn'不会给(i,i)对(又名开始和结束行是相同的),如果我们有一个向量,在选定的子向量中永远不会包含0(例如'y < - c(1,0,1)')。 – josliber