2017-03-29 17 views
0

我有一個具有E型SKU或非E型SKU的數據集。我的目標是找出我是否以任何順序銷售E型SKU以及類似的非E型SKU。按組查找特定項目的行復制

例如,如果我用W123出售E123,這將被視爲重複。如果我將E123與另一個E123一起銷售,這不會被視爲重複。如果我用W123出售W123,它也不會被視爲重複。總而言之,我需要找到至少有一個E型SKU和至少一個非E型SKU的副本。

我在SO上詢問的上一個示例與此類似(Find row-wise duplicates by groups),但該方法的挑戰在於,當應用sub("^E","", Product)時,我不再知道我是在比較E型SKU與E型SKU還是E非E型SKU的SKU型SKU。

這裏的樣本數據:

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") 

這裏的預期輸出:

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") 

這是我的工作代碼:

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) 

我有兩個問題:

a)如何我是否使用data.table做我想做的事情? b)有沒有更快的方法來做到這一點?我問這是因爲在我的原始數據集上,它有大約1M行,上面的代碼是永久的。

回答

1

我們可以在data.table中做到這一點。將'data.frame'轉換爲'data.table'(setDT(Test_File)),通過匹配數字和非數字字符並將其替換爲空白來提取非數字('v1')和數字子字符串,然後按'Order '我們檢查是否存在any是E的非數字字符以及lengthunique非數字字符的元素大於1,並且數字部分有任何重複字符。

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 

注:可能是更好地保持爲邏輯欄( '副本'),而不是 'Y/N'

+1

謝謝。你是一個天才 - 你做了兩行只有10行的東西。你介意解釋你做了什麼?我不太熟悉'data.table',我仍然在學習...... – watchtower

+0

謝謝。你知道在sub()中寫表達式的好資源嗎?我總是爲此而掙扎。我剛剛瞭解了'\\ d +'和'\\ D +'... – watchtower

+1

@watchtower我添加了一些說明。讓我知道如果你需要進一步的解釋 – akrun