2016-10-25 4 views
2

Ich habe eine data.table mit zwei Parametern (Datum und Status), jetzt möchte ich neue Spalten basierend auf der ursprünglichen Tabelle einfügen.Gruppenfunktion mit Grundberechnung

Datenregeln:

  1. die Spalte-Status enthält nur "0" und "1"
  2. die Datumsspalte wird immer von Sekunden erhöhen :)

neue Variablen:

  1. Gruppe: um jede Gruppe oder jeden Zyklus für den Status zu nummerieren, ist die Reihenfolge des Status (0,1). es bedeutet, dass der Status mit dem Status '0' beginnt, wenn der Status wieder '0' wird, ist ein Zyklus abgeschlossen.
  2. cycle_time: Die Zykluszeit für jede Gruppe
  3. group_0 berechnen: die Zeit für den Status 0 innerhalb einer bestimmten Gruppe
  4. GROUP_1 berechnen: die Zeit für den Status 1 innerhalb einer bestimmten Gruppe

berechnen zum Beispiel kann eine einfache Eingabe:

enter image description here

der Code die Daten zu erzeugen:

dd <- data.table(date = c("2015-07-01 00:00:12", "2015-07-01 00:00:13","2015-07-01 00:00:14","2015-07-01 00:00:15", "2015-07-01 00:00:16", "2015-07-01 00:00:17","2015-07-01 00:00:18", "2015-07-01 00:00:19", "2015-07-01 00:00:20","2015-07-01 00:00:21", "2015-07-01 00:00:22", "2015-07-01 00:00:23","2015-07-01 00:00:24", "2015-07-01 00:00:25"), status = c(0,0,0,0,1,1,1,0,0,1,1,1,1,0)) 

die Ausgabe neuer Parameter einschließlich ist:

enter image description here

Ich habe tatsächlich mit einigen grundlegenden Methoden getan,

  1. die Hauptidee ist: Wenn der aktuelle Zustand 0 und das ist Der nächste Status ist 1, dann markieren Sie ihn als eine Gruppe.
  2. Die Idee könnte funktionieren, aber das Problem ist die Rechenzeit ist zu lang, da so viele Schleifen.

ich angenommen, dass es 1 bis 0 markiert die Grenze einer Gruppe

+0

[? Wie ein großes R reproduzierbares Beispiel machen] (http://stackoverflow.com/questions/5963269) – zx8754

Antwort

2

So ein Übergang eine einfachere Lösung für diesen Fall sein könnte. Sie können cumsum und diff verwenden, um dies zu erreichen. Für die x Beispiel in der Antwort von @ zx8754:

data.frame(x, group_id = c(1, cumsum(diff(x) == -1) + 1)) 
    x group_id 
1 0  1 
2 0  1 
3 0  1 
4 1  1 
5 1  1 
6 0  2 
7 0  2 
8 1  2 
9 0  3 

Für eine realistischere Größe Beispiel:

res = data.frame(status = sample(c(0,1), 10e7, replace = TRUE)) 
system.time(res$group_id <- c(1, cumsum(diff(res$status) == -1) + 1)) 
    user system elapsed 
    2.770 1.680 4.449 
>  head(res, 20) 
    status group_id 
1  0  1 
2  0  1 
3  1  1 
4  0  2 
5  0  2 
6  0  2 
7  1  2 
8  1  2 
9  0  3 
10  1  3 
11  1  3 
12  0  4 
13  1  4 
14  0  5 
15  0  5 
16  1  5 
17  0  6 
18  0  6 
19  1  6 
20  0  7 

5 Sekunden 10 Millionen Datensätze recht schnell ist (obwohl das hängt von Ihrer Definition von schnellen :)).


Benchmarking

set.seed(1) 
res = data.frame(status = sample(c(0,1), 10e4, replace = TRUE)) 

microbenchmark::microbenchmark(
    rleid = { 
    gr <- data.table::rleid(res$status) 
    x1 <- as.numeric(as.factor(ifelse(gr %% 2 == 0, gr - 1, gr))) 
    # removing "as.numeric(as.factor" helps, but still not as fast as cumsum 
    #x1 <- ifelse(gr %% 2 == 0, gr - 1, gr) 
    }, 
    cumsum = { x2 <- c(1, cumsum(diff(res$status) == -1) + 1) } 
) 

# Unit: milliseconds 
# expr  min   lq  mean  median   uq  max neval cld 
# rleid 118.161287 120.149619 122.673747 121.736122 123.271881 168.88777 100 b 
# cumsum 1.511811 1.559563 2.221273 1.826404 2.475402 6.88169 100 a 

identical(x1, x2) 
# [1] TRUE 
+1

Ich denke group_id sollte bis zur nächsten 0 gleich bleiben, dh: '0,0,1,0,1' sollte' 1,1,1,2,2' sein. – zx8754

+0

hallo danke für die idee, aber schau dir die definition der gruppe in diesem fall an. Basierend auf Ihren Daten sind die Zeilen von 1 bis 3 in der gleichen Gruppe eins, und die Reihen von vier und fünf ist die zweite Gruppe :) – ZAWD

+0

@ zx8754 genau :) danke! – ZAWD

2

Try this:

#dummy data 
x <- c(0,0,0,1,1,0,0,1,0) 

#get group id using rleid from data.table 
gr <- data.table::rleid(x) 

#merge separated 0,1 groups 
gr <- ifelse(gr %% 2 == 0, gr - 1, gr) 

#result 
cbind(x, gr) 
#  x gr 
# [1,] 0 1 
# [2,] 0 1 
# [3,] 0 1 
# [4,] 1 1 
# [5,] 1 1 
# [6,] 0 3 
# [7,] 0 3 
# [8,] 1 3 
# [9,] 0 5 

#if we need to have group names sequential then 
cbind(x, gr = as.numeric(as.factor(gr))) 
#  x gr 
# [1,] 0 1 
# [2,] 0 1 
# [3,] 0 1 
# [4,] 1 1 
# [5,] 1 1 
# [6,] 0 2 
# [7,] 0 2 
# [8,] 1 2 
# [9,] 0 3 
+1

+1, obwohl meine obige Lösung mit 'diff' und' cumsum' viel kürzer im Code und wahrscheinlich schneller ist (obwohl ich das nicht getestet habe)? –

+0

Hallo, vielen Dank für die Lösung, aber immer noch schneller als meine Lösung :) Danke! – ZAWD

Verwandte Themen