2013-11-15 25 views
9

Ich möchte eine laufende Nummer innerhalb jedes Laufs von gleichen Werten, wie ein Zähler von Vorkommen, erstellen, der neu startet, sobald der Wert in der aktuellen Reihe von der vorherigen Reihe abweicht.R: Zähle aufeinanderfolgende Vorkommen von Werten in einer einzigen Spalte

Nachfolgend finden Sie ein Beispiel für die Eingabe und die erwartete Ausgabe.

dataset <- data.frame(input = c("a","b","b","a","a","c","a","a","a","a","b","c")) 
dataset$counter <- c(1,1,2,1,2,1,1,2,3,4,1,1) 
dataset 

# input counter 
# 1  a  1 
# 2  b  1 
# 3  b  2 
# 4  a  1 
# 5  a  2 
# 6  c  1 
# 7  a  1 
# 8  a  2 
# 9  a  3 
# 10  a  4 
# 11  b  1 
# 12  c  1 

Meine Frage ist sehr ähnlich wie diese: Cumulative sequence of occurrences of values.

Antwort

27

Sie müssen sequence und rle verwenden:

> sequence(rle(as.character(dataset$input))$lengths) 
[1] 1 1 2 1 2 1 1 2 3 4 1 1 
+0

Cheers, das funktioniert wie ein Charme! Woher weißt du über den $ längen Teil? Gibt es andere Eigenschaften? (Ich sehe sie nicht in R Docs). – Richard

+2

@Richard, siehe Abschnitt "Wert" in der Dokumentation zu '? Rle'. Die zwei zurückgegebenen Werte (in einer "Liste" von "Klasse" "rle") sind "Längen" und "Werte". – A5C1D2H2I1M1N2O1R2T1

13

Eine effiziente und einfachere Version der Funktion unten geschrieben sind ab sofort in data.table Paket, genannt rleid. Mit, dass, es ist nur:

setDT(dataset)[, counter := seq_len(.N), by=rleid(input)] 

?rleid Siehe für mehr Verbrauch und Beispiele. Danke an @Henrik für den Vorschlag, diesen Beitrag zu aktualisieren.


rle ist auf jeden Fall der bequemste Weg, es zu tun (+1 @ Ananda). Aber bei größeren Daten könnte man (in Bezug auf die Geschwindigkeit) besser sein. Sie können die duplist und vecseq Funktionen (nicht exportiert) aus data.table wie folgt verwenden:

require(data.table) 
arun <- function(y) { 
    w = data.table:::duplist(list(y)) 
    w = c(diff(w), length(y)-tail(w,1L)+1L) 
    data.table:::vecseq(rep(1L, length(w)), w, length(y)) 
} 

x <- c("a","b","b","a","a","c","a","a","a","a","b","c") 
arun(x) 
# [1] 1 1 2 1 2 1 1 2 3 4 1 1 

Benchmarking auf große Datenmengen:

set.seed(1) 
x <- sample(letters, 1e6, TRUE) 
# rle solution 
ananda <- function(y) { 
    sequence(rle(y)$lengths) 
} 

require(microbenchmark) 
microbenchmark(a1 <- arun(x), a2<-ananda(x), times=100) 
Unit: milliseconds 
      expr  min  lq median  uq  max neval 
    a1 <- arun(x) 123.2827 132.6777 163.3844 185.439 563.5825 100 
a2 <- ananda(x) 1382.1752 1899.2517 2066.4185 2247.233 3764.0040 100 

identical(a1, a2) # [1] TRUE 
+10

Nicht gerecht mit Ihren super-Duper-geheimen Funktionen! :-(....... +1 – A5C1D2H2I1M1N2O1R2T1

+0

@Arun, danke, dies ist ein etwas kleinerer Datensatz, an dem ich gerade arbeite, aber es wird in Zukunft sicher nützlich sein! Es tut mir leid, ich kann nur eine Antwort akzeptieren! :( – Richard

+2

Hallo @Arun - Ich denke, duplist ist nicht in der neuesten Version von 'data.table' Version 1.9.2 – vrajs5

Verwandte Themen