2017-03-29 3 views
0

Ich habe einen Datensatz mit einer E-Typ-SKU oder Nicht-E-Typ-SKU. Mein Ziel ist es herauszufinden, ob ich in irgendeiner Reihenfolge eine E-Typ-SKU zusammen mit einer ähnlichen Nicht-E-Typ-SKU verkauft habe.Suchen Sie zeilenweise Duplikate nach Gruppen für einen bestimmten Artikel

Zum Beispiel, wenn ich E123 mit W123 verkauft habe, wird dies als doppelt angesehen. Wenn ich E123 mit einem anderen E123 verkaufe, wird dies nicht als Duplikat angesehen. Wenn ich W123 mit W123 verkaufte, wird es auch nicht als Duplikat betrachtet. Zusammenfassend muss ich ein Duplikat finden, das mindestens eine E-Typ-SKU und mindestens eine Nicht-E-Typ-SKU aufweist.

Das vorherige Beispiel I SO gebeten ist ähnlich (Find row-wise duplicates by groups), aber die Herausforderung mit dieser Methode ist, dass, wenn sub("^E","", Product) angewandt wird, ich weiß nicht mehr, ob ich eine E-Typ-SKU mit E-Typ SKU bin im Vergleich oder eine E -Typ SKU mit Nicht-E-Typ SKU.

Hier Beispieldaten:

dput(Test_File) 
structure(list(Order = c(1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 
5, 5), Product = c("E12960", "E12960", "E12960", "W12960", "W12960", 
"W12960", "E1234", "E2345", "W2355", "A1235", "C-A-1234", "W-1234", 
"A-1234", "C-1234")), .Names = c("Order", "Product"), row.names = c(NA, 
14L), class = "data.frame") 

Hier wird erwartet, Ausgang:

dput(Output_File) 
structure(list(Order = c(1, 2, 3, 4, 5), Duplicate = c("N", "Y", 
"N", "N", "N")), .Names = c("Order", "Duplicate"), row.names = c(NA, 
5L), class = "data.frame") 

Hier ist meine Arbeitscode:

Test_File[,"ESKU_Present"]<-grepl("^E",Test_File$Product,ignore.case = TRUE) 

#Strip initial identifiers 
toMatch<-c("^E","^W","^A","^C-","^W-","C-A-","^A-") 
Test_File[grepl(paste(toMatch,collapse="|"),Test_File$Product,ignore.case = TRUE),"New_Product_ID"]<-sub(paste(toMatch,collapse="|"), "", Test_File$Product) 

Output <- Test_File %>% 
    dplyr::group_by(Order) %>% 
    #find those orders that have at least one ESKU and one non-ESKU 
    mutate(Duplicate = (any(ESKU_Present ==c("FALSE")) & any(ESKU_Present == c("TRUE")))) %>% 
    dplyr::filter(Duplicate == "TRUE") %>% 
    dplyr::summarise(Final_Flag = any(duplicated(New_Product_ID))) %>% 
    right_join(Test_File) %>% 
    dplyr::select(Order, Final_Flag) 

Output[is.na(Output$Final_Flag),"Final_Flag"]<-FALSE 
Output<-dplyr::distinct(Output) 

Ich habe zwei Fragen:

a) Wie verwende ich data.table zu tun, was ich versuche zu tun? b) Gibt es einen schnelleren Weg, dies zu tun? Ich frage das, weil auf meinem ursprünglichen Datensatz, der ungefähr 1M Reihen hat, der oben genannte Code ewig dauert.

Antwort

1

Wir können dies in data.table tun. Konvertieren Sie den 'data.frame' in 'data.table' (setDT(Test_File)), extrahieren Sie die nicht numerische ('v1') und numerische Teilzeichenfolge, indem Sie die numerischen und nicht numerischen Zeichen mit Leerzeichen ersetzen und dann nach 'Reihenfolge' gruppieren Wir prüfen, ob any nicht-numerisches Zeichen, das ein 'E' ist, und die length von unique Elemente für nicht-numerische Zeichen ist größer als 1 und es gibt doppelte Zeichen für numerische Teil.

library(data.table) 
setDT(Test_File)[, { 
      v1 <- sub("\\d+", "", Product) 
      v2 <- sub("\\D+", "", Product) 
     .(Duplicate = any(v1=="E") & uniqueN(v1)>1 & anyDuplicated(v2)>0)} , Order] 
#  Order Duplicate 
#1:  1  FALSE 
#2:  2  TRUE 
#3:  3  FALSE 
#4:  4  FALSE 
#5:  5  FALSE 

HINWEIS: Es kann besser sein als logische Spalte zu halten ('Duplikat') anstelle von 'Y/N'

+1

Danke. Du bist ein Genie - du hast getan, was 10 Zeilen in nur zwei Zeilen brachte. Stört es Sie zu erklären, was Sie getan haben? Ich bin nicht vertraut mit 'data.table' und lerne immer noch ... – watchtower

+0

Danke. Kennen Sie eine gute Ressource zum Schreiben von Ausdrücken in 'sub()'? Ich kämpfe immer damit. Ich habe gerade über '\\ d +' und '\\ D +' jetzt erfahren ... – watchtower

+1

@watchtower Ich habe eine Beschreibung hinzugefügt. Lassen Sie mich wissen, wenn Sie weitere Erläuterungen benötigen – akrun

Verwandte Themen