2016-03-08 48 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