2013-05-28 6 views
5

Ich möchte meine Daten in Gruppen von aufeinanderfolgenden Zeilen teilen, die einen Test bestehen. Hier ein Beispiel:Aufteilen (1: n) [boolean] in zusammenhängende Sequenzen

set.seed(1) 
n <- 29 
ok <- sample(c(TRUE,FALSE),n,replace=TRUE,prob=c(.7,.3)) 

vec <- (1:n)[ok] 
# [1] 1 2 3 5 8 9 10 11 12 13 14 16 19 22 23 24 25 26 27 28 

Die gewünschte Ausgabe wird "VEC" gruppiert in zusammenhängende Sequenzen:

out <- list(1:3,5,8:14,16,19,22:28) 

Dies funktioniert:

nv <- length(vec) 

splits <- 1 + which(diff(vec) != 1) 
splits <- c(1,splits,nv+1) 
nsp <- length(splits) 

out <- list() 
for (i in 1:(nsp-1)){ 
    out[[i]] <- vec[splits[i]:(splits[i+1]-1)] 
} 

Ich vermute, es ist ein sauberer Weg in der Basis R ...? Ich bin noch nicht geschickt mit den rle und cumsum Tricks, die ich auf SO gesehen habe ...

Antwort

6

hier ein cumsum "Trick" für Sie:

split(vec, cumsum(c(1, diff(vec)) - 1)) 

Update

Hier ein einfaches Beispiel Ihrer Version split(vec, cumsum(c(0, diff(vec) > 1))) bei jedem Schritt unter Verwendung von aufgeschlüsselt:

vec <- c(1:3,7:9)   # 1 2 3 7 8 9 (sample with two contiguous sequences) 
diff(vec)     # 1 1 4 1 1 (lagged difference) 
diff(vec) > 1    # F F T F F (not contiguous where diff > 1) 
          # 0 0 1 0 0 (numeric equivalent for T/F) 
c(0, diff(vec) > 1)   # 0 0 0 1 0 0 (pad with 0 to align with original vector) 
cumsum(c(0, diff(vec) > 1)) # 0 0 0 1 1 1 (cumulative sum of logical values) 

groups <- cumsum(c(0, diff(vec) > 1)) # 0 0 0 1 1 1 

sets <- split(vec, groups) # split into groups named by cumulative sum 

sets 
# $`0` 
# [1] 1 2 3 
# 
# $`1` 
# [1] 7 8 9 

Und dann wenn Sie es aus irgendeinem Grund ausgeben möchten:

+0

Danke. Nachdem ich Ihre Lösung seziert hatte, fand ich, dass ich diese Form bevorzuge: 'split (vec, cumsum (c (0, diff (vec)> 1))). – Frank