2016-08-23 1 views
1

Ich bin ein R noob und versuche, eine Zusammenfassung für ein Dataset durchzuführen, die die Anzahl der Ereignistypen für jede ID umfasst, die zwischen Ereignissen vom Typ 'B' für diese ID aufgetreten ist . Hier ist ein Beispiel zur Veranschaulichung:Bedingte Zusammenfassung von Gruppen in dplyr basierend auf dem Datum

id <- c('1', '1', '1', '2', '2', '2', '3', '3', '3', '3') 
type <- c('A', 'A', 'B', 'A', 'B', 'C', 'A', 'B', 'C', 'B') 
datestamp <- as.Date(c('2016-06-20','2016-07-16','2016-08-14','2016-07-17' 
         ,'2016-07-18','2016-07-19','2016-07-16','2016-07-19' 
         , '2016-07-21','2016-08-20')) 
df <- data.frame(id, type, datestamp) 

, die produziert:

> df 
    id type datestamp 
1 1 A 2016-06-20 
2 1 A 2016-07-16 
3 1 B 2016-08-14 
4 2 A 2016-07-17 
5 2 B 2016-07-18 
6 2 C 2016-07-19 
7 3 A 2016-07-16 
8 3 B 2016-07-19 
9 3 C 2016-07-21 
10 3 B 2016-08-20 

Jedes Mal, wenn ein Ereignis ‚B‘ auf, ich die Anzahl der jeden Ereignistyp wissen wollen, die vor diesem B Ereignis aufgetreten ist, aber nach anderen B-Ereignissen für diese ID. Was möchte ich mit, um am Ende eine Tabelle wie folgt aus:

id type B_instance count 
1 1 A   1  2 
2 2 A   1  1 
3 3 A   1  1 
4 3 C   2  1 

in der Erforschung, diese Frage kam in der Nähe: summarizing a field based on the value of another field in dplyr

Ich habe versucht, diese Arbeit zu machen:

df2 <- df %>% 
    group_by(id, type) %>% 
    summarize(count = count(id[which(datestamp < datestamp[type =='B'])])) %>% 
    filter(type != 'B') 

Aber es Fehler aus (auch, selbst wenn es funktioniert, ist es nicht berücksichtigt 2 Ereignisse ‚B‘ in der gleichen ID, wie mit id = 3)

Antwort

0

Sie 0 verwenden können, um die neue Gruppenvariable B_instance zu erstellen, indem Sie cumsum(type == "B") ausführen und dann Typen herausfiltern, die hinter dem letzten B sowie Typ B selbst liegen, da sie nicht gezählt werden. Verwenden Sie dann count, um das Auftreten mit der Gruppe durch id, B_instance und type zu zählen.

df %>% 
     group_by(id) %>% 
     # create B_instance using cumsum on the type == "B" condition 
     mutate(B_instance = cumsum(type == "B") + 1) %>%  
     # filter out rows with type behind the last B and all B types     
     filter(B_instance < max(B_instance), type != "B") %>% 
     # count the occurrences of type grouped by id and B_instance 
     count(id, type, B_instance) 

# Source: local data frame [4 x 4] 
# Groups: id, type [?] 

#  id type B_instance  n 
# <fctr> <fctr>  <dbl> <int> 
# 1  1  A   1  2 
# 2  2  A   1  1 
# 3  3  A   1  1 
# 4  3  C   2  1 
+0

das funktioniert perfekt! Danke! aus Neugier, warum die Instanz erhöht werden muss cumsum müssen von 1? – feyr

+0

Passend zu zählen, sonst wird es von Null anfangen, und das Ergebnis wird sei wie "0,0,0,1" statt "1,1,1,2". – Psidom

1

Hier ist eine Option mit data.table. Wir konvertieren den 'data.frame' in 'data.table' (setDT(df), gruppiert nach 'id', wir erhalten die Sequenz der max Position, wo 'type' ist 'B', finde den Zeilenindex (.I), extrahiere das Spalte ($V1). Dann unterteilen wir die Datenmenge (df[i1]), entfernen Sie die Zeilen, wo "Typ" ist "B", gruppiert nach "ID", "Typ" und die rleid von "Typ", erhalten wir die Anzahl der Zeilen als ‚count‘.

library(data.table) 
i1 <- setDT(df)[, .I[seq(max(which(type=="B")))] , by = id]$V1 
df[i1][type!="B"][, .(count = .N), .(id, type, B_instance = rleid(type))] 
# id type B_instance count 
#1: 1 A  1  2 
#2: 2 A  1  1 
#3: 3 A  1  1 
#4: 3 C  2  1 
+1

Das funktioniert auch sehr gut, danke. @ Psidom's Die dplyr-Lösung macht mir einen intuitiveren Sinn. Aber hat die Verwendung einer data.table Vorteile, die mir nicht bekannt ist? Oder nur persönliche Vorliebe? – feyr

+0

@feyr Beide sind gute Pakete. Wenn Sie die Zuweisung an Ort und Stelle nutzen möchten (': ='), (was hier nicht gemacht wird) welche data.table tut und effizient wäre. In diesem Fall wird die Lösung von psidom so gut wie meine oder noch eleganter. – akrun

Verwandte Themen