2016-03-15 55 views
11

我正在尋找使用grep/like/stri_detect條件在字符列上連接2個data.frames/data.tables的有效方法。R加入like/grep條件

我能夠使用sqldf包加入like,但速度很慢。在我的2個data.tables(5k行,20k行)大約需要60秒。

我的第二種方法是從data.table中使用CJ,然後在2列上使用stri_detect_fixed。這種方法更快(16秒),但我擔心隨着數據的增長,它將無法使用(它會顯着增加內存使用率)。

我也試過在for循環中做它,但它是最慢的一個。

有沒有辦法做得更快,尤其是在data.table?

下面我貼我的例子:

library(stringi) 
library(data.table) 
library(sqldf) 
data1 <- data.table(col1 = paste0(c("asdasd asdasd 768jjhknmnmnj", 
"78967ggh","kl00896754","kl008jku"),1:10000)) 

data2 <- data.table(col2 = paste0(c("mnj", "12345","kl008","lll1"), 1:10000)) 

system.time(join1 <- data.table(sqldf("select * 
      from data1 a inner join data2 b 
         on a.col1 like '%' || b.col2 || '%'", drv = "SQLite"))) 



system.time(kartezjan <- CJ(col1 = data1[,c("col1"), with = F][[1]], 
          col2 = data2[,c("col2"), with = F][[1]], 
unique = TRUE)[stri_detect_fixed(col1, col2, case_insensitive = FALSE)]) 
+0

在我的機器上,sqldf代碼耗時89.02秒,它使用'on instr(a.col1,b.col2)'而不是'on ... like ...'和696秒使用數據409.35秒。表。有一個'library(stringi)'調用丟失。 –

+0

你的例子的結果是不同的。也許你應該舉一個簡單的例子,並解釋你想在角落案件中發生的事情。 (col1中的值不匹配,col2中的值沒有匹配和多個匹配的可能性)。另外,知道值是否有一些限制也是有幫助的。 – bluefish

+0

我使用'instr'來檢查它,但它比'on ... like ...'慢。現在我添加庫並將左連接更改爲內連接以使結果相同。 – Kacper

回答

1

sqldf的做法是在我的機器上速度最快的爲您的示例數據,但這裏是一個更快data.table版本的情況下,它幫助。

library(data.table) 
library(sqldf) 

## Example data 
v1 <- paste0(c("asdasd asdasd 768jjhknmnmnj", "78967ggh","kl00896754","kl008jku"), 
    1:10000) 
v2 <- paste0(c("mnj", "12345","kl008","lll1"), 1:10000) 

data1 <- data.table(col1=v1, key="col1") 
data2 <- data.table(col2=v2, key="col2") 


## sqldf version 
system.time(
    ans1 <- data.table(sqldf(
    "select * 
    from data1 a inner join data2 b 
    on instr(a.col1, b.col2)", drv="SQLite")) 
) 

## user system elapsed 
## 17.579 0.036 17.654 


## parallelized data.table version 
suppressMessages(library(foreach)); suppressMessages(library(doParallel)) 
cores <- detectCores() ## I've got 4... 
clust <- makeForkCluster(cores) 
registerDoParallel(clust) 

system.time({ 
    batches <- cores 
    data2[, group:=sort(rep_len(1:batches, nrow(data2)))] 
    ans2 <- foreach(
    i=1:batches, .combine=function(...) rbindlist(list(...)), 
    .multicombine=TRUE, .inorder=FALSE) %dopar% { 
     CJ(col1=data1[, col1], col2=data2[group==i, col2])[, 
     alike:=col1 %like% col2, by=col2][ 
      alike==TRUE][, alike:=NULL][]   
    } 
}) 

## user system elapsed 
## 0.185 0.229 30.295 

stopCluster(clust) 
stopImplicitCluster() 

我在OSX上運行這個 - 你可能需要調整其他操作系統的並行代碼。另外,如果您的實際數據較大並且內存不足,則可以嘗試較大的值batches