2011-02-16 76 views
16

我有一個小時值。我想要統計自上次不爲零以來該值爲零的連續小時數。對於電子表格或循環來說,這是一件容易的工作,但我希望有一個精簡的矢量化單線程來完成任務。計算有多少連續值爲真

x <- c(1, 0, 1, 0, 0, 0, 1, 1, 0, 0) 
df <- data.frame(x, zcount = NA) 

df$zcount[1] <- ifelse(df$x[1] == 0, 1, 0) 
for(i in 2:nrow(df)) 
    df$zcount[i] <- ifelse(df$x[i] == 0, df$zcount[i - 1] + 1, 0) 

所需的輸出:

R> df 
    x zcount 
1 1  0 
2 0  1 
3 1  0 
4 0  1 
5 0  2 
6 0  3 
7 1  0 
8 1  0 
9 0  1 
10 0  2 

回答

21

這裏有一個方法,建立在約書亞的rle方式: (編輯根據Marek的建議使用​​和lapply

> (!x) * unlist(lapply(rle(x)$lengths, seq_len)) 
[1] 0 1 0 1 2 3 0 0 1 2 

UPDATE。只是踢,這裏是另一種方式來做到這一點,圍繞快5倍:

cumul_zeros <- function(x) { 
    x <- !x 
    rl <- rle(x) 
    len <- rl$lengths 
    v <- rl$values 
    cumLen <- cumsum(len) 
    z <- x 
    # replace the 0 at the end of each zero-block in z by the 
    # negative of the length of the preceding 1-block.... 
    iDrops <- c(0, diff(v)) < 0 
    z[ cumLen[ iDrops ] ] <- -len[ c(iDrops[-1],FALSE) ] 
    # ... to ensure that the cumsum below does the right thing. 
    # We zap the cumsum with x so only the cumsums for the 1-blocks survive: 
    x*cumsum(z) 
} 

嘗試一個例子:

> x <- sample(0:1, 1000000,T) 
> system.time(z <- cumul_zeros(x)) 
    user system elapsed 
    0.15 0.00 0.14 
> system.time(z <- (!x) * unlist(lapply(rle(x)$lengths, seq_len))) 
    user system elapsed 
    0.75 0.00 0.75 

> cumul_zeros(c(1,1,1,0,0,0,0,0,1,1,1,0,0,1,1)) 
[1] 0 0 0 1 2 3 4 5 0 0 0 1 2 0 0 

現在上萬長向量比較倍

故事的道德:單行者更好,更容易理解,但並不總是最快的!

+2

+1精彩單線。小代碼分析:`(!x)* unlist(lapply(rle(x)$ lengths,seq_len))(`lapply`更安全更快,`seq_len`是`seq`的簡化版本),大約快2倍。 – Marek 2011-02-16 12:16:30

6

rle將「計數的值多少個連續小時自上一次它不是零過零」,而不是在你的「所需的輸出格式」。

注意長度爲其中相應的值爲零的元素:

rle(x) 
# Run Length Encoding 
# lengths: int [1:6] 1 1 1 3 2 2 
# values : num [1:6] 1 0 1 0 1 0 
+1

方便,但我不能得到我需要從rle沒有做一些非常不雅的東西。 – 2011-02-16 05:53:07

3

的一行,不完全是超優雅:

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

unlist(lapply(split(x, c(0, cumsum(abs(diff(!x == 0))))), function(x) (x[1] == 0) * seq(length(x)))) 
22

William Dunlap在R-Help上的帖子是查找與遊程長度相關的所有內容的地方。他從this post F7是

f7 <- function(x){ tmp<-cumsum(x);tmp-cummax((!x)*tmp)} 

,並在當前形勢下f7(!x)。在性能方面有

> x <- sample(0:1, 1000000, TRUE) 
> system.time(res7 <- f7(!x)) 
    user system elapsed 
    0.076 0.000 0.077 
> system.time(res0 <- cumul_zeros(x)) 
    user system elapsed 
    0.345 0.003 0.349 
> identical(res7, res0) 
[1] TRUE