2017-12-30 11 views
1

Ich möchte eine Datentabelle aufteilen, um Datensätze basierend auf ihren Daten und bedingten Werten von zwei anderen Spalten (ID und Typ Variablen) aufzunehmen. Wenn jedoch nur ein Datensatz pro ID vorhanden ist, behalten Sie den Datensatz bei, unabhängig vom Wert der anderen bedingten Spalte oder des Datums.Wenn Spaltenwert dupliziert wird, dann Zeile basierend auf mehreren Bedingungen beibehalten, ansonsten Zeile

Eine Probe meiner Daten sieht wie folgt aus:

dt <- data.table(badge = c("1001", "1001", "1002", "1003", "1003", "1003", "1004", "1004"), location = c("training", "test", "training", "training", "test", "test", "training", "training"), date = as.POSIXct(c("2014-09-21", "2014-10-01", "2014-09-20", "2014-09-15", "2014-11-01", "2014-12-10", "2014-09-09", "2014-09-10")), score = as.numeric(c(3,5,-1,0,1,3,-2,1))) 

> dt 
    badge location  date score 
1: 1001 training 2014-09-21  3 
2: 1001  test 2014-10-01  5 
3: 1002 training 2014-09-20 -1 
4: 1003 training 2014-09-15  0 
5: 1003  test 2014-11-01  1 
6: 1003  test 2014-12-10  3 
7: 1004 training 2014-09-09 -2 
8: 1004 training 2014-09-10  1 

Für jedes Abzeichen, ich bin mehr daran interessiert, die Testergebnisse über die Trainings Score (Zeile # 2). Wenn jedoch keine Testergebnisse für ein bestimmtes Badge vorhanden sind, möchte ich die Trainingsbewertung beibehalten (Zeile 3). Wenn mehr als ein Testergebnis pro Abzeichen vorhanden ist, möchte ich das Ergebnis zu dem früheren Datum (Zeile 5) übernehmen. Wenn mehr als ein Trainingsergebnis pro Abzeichen vorhanden ist, aber kein Testergebnis, möchte ich das Ergebnis zu einem späteren Zeitpunkt (Zeile 8) nehmen.

Das Ergebnis sollte wie folgt aussehen:

> dt 
    badge location  date score 
2: 1001  test 2014-10-01  5 
3: 1002 training 2014-09-20 -1 
5: 1003  test 2014-11-01  1 
8: 1004 training 2014-09-10  1 

Ich habe versucht, Variationen verschiedener dplyr Saiten und subsetting. dt <- dt %>% group_by(badge) %>% filter(location=="test") %>% filter(date == min(date)) ist das nächste, das ich bekommen habe, da es mir die frühesten Testergebnisse per Abzeichen gibt, aber alle Trainingsaufzeichnungen entfernt werden, unabhängig davon, ob es einen Testergebnis für dieses Abzeichen gibt. Ich kann verstehen, warum dieser Code nicht funktioniert, da ich ihn selektiv betrachte, aber ich weiß nicht, wie ich ihn nuancierter gestalten kann, um das gewünschte Ergebnis zu erzielen.

Antwort

2

Hier ist eine alternative Lösung, die nur einmal bestellt wiederholt Umordnung zu vermeiden, während die Gruppierung:

library(data.table) 
tmp <- dt[order(date), if (any(location == "test")) 
    first(.I[location == "test"]) else last(.I), keyby = badge] 
dt[tmp$V1] 
badge location  date score 
1: 1001  test 2014-10-01  5 
2: 1002 training 2014-09-20 -1 
3: 1003  test 2014-11-01  1 
4: 1004 training 2014-09-10  1 

Zur besseren Erklärung, ich tmp eingeführt haben, obwohl dies erforderlich ist nicht wirklich. tmp hält die Indizes der ausgewählten Datensätze in V1:

badge V1 
1: 1001 2 
2: 1002 3 
3: 1003 5 
4: 1004 8 
+0

Ich wählte diese Antwort für ihre Einfachheit und Kürze. Vielen Dank! – ktf

3

Ich denke, das ist die Logik, die Sie wollen:

library(data.table) 
myfunc <- function(x) { 
if (!'test' %in% x$location) { 
    out <- setorder(x, -date) 
} else { 
    out <- setorder(x, location, date) 
} 
out[1, ] 
} 

dt[, myfunc(.SD), by = 'badge'] 
# badge location  date score 
#1: 1003  test 2014-11-01  1 
#2: 1001  test 2014-10-01  5 
#3: 1002 training 2014-09-20 -1 
#4: 1004 training 2014-09-10  1 

ich eine benutzerdefinierte Funktion auf Ihrer Logik gemacht und auf jeder Abzeichen Gruppe verwendet (die data.table und gibt die erste Reihe zu bestellen).

1

Eine andere mögliche Lösung mit dplyr ist die Verwendung von filter, join und union_all.

library(data.table) 
library(dplyr) 


    dt <- data.table(badge = c("1001", "1001", "1002", "1003", "1003", "1003", "1004", "1004"), 
location = c("training", "test", "training", "training", "test", "test", "training", "training"), 
date = as.POSIXct(c("2014-09-21", "2014-10-01", "2014-09-20", "2014-09-15", "2014-11-01", "2014-12-10", "2014-09-09", "2014-09-10")), 
score = as.numeric(c(3,5,-1,0,1,3,-2,1))) 


     # Rows with badge having both "test" and "training". Data with "test" is preferred 
     df_test <- dt %>% filter(location == "test") %>% 
     inner_join(filter(dt, location == "training"), by="badge") %>% 
     select(badge, location = location.x, date = date.x, score = score.x) 

     # Data for badge with only "training" records 
     df_training <- dt %>% filter(location == "training") %>% 
      anti_join(filter(dt, location == "test"), by="badge") 

     # combine both 
     union_all(df_test, df_training) 

     # The result will look like: 
     > union_all(df_test, df_training) 
      badge location  date score 
     1 1001  test 2014-10-01  5 
     2 1003  test 2014-11-01  1 
     3 1003  test 2014-12-10  3 
     4 1002 training 2014-09-20 -1 
     5 1004 training 2014-09-09 -2 
     6 1004 training 2014-09-10  1 

Nicht sicher, ob OP duplicate Aufzeichnungen in same location halten will. Wenn doppelte Datensätze nicht benötigt werden, können diese mit distinct herausgefiltert werden.

+0

Bitte überprüfen Sie Ihre Antwort, da es nicht das erwartete Ergebnis zurückgibt. Insbesondere hat das OP erklärt, dass doppelte Eingaben für Test- und Trainingsfälle unterschiedlich behandelt werden sollen. Also, es ist mehr als nur 'distinct()' zu verwenden. – Uwe

Verwandte Themen