2016-03-15 18 views
11

Tôi đang tìm cách hiệu quả để tham gia 2 data.frames/data.tables trên cột ký tự sử dụng điều kiện grep/like/stri_detect.R tham gia vào/grep điều kiện

Tôi có thể sử dụng gói sqldf với tham gia tương tự, nhưng khá chậm. Trên 2 data.tables của tôi (5k hàng, 20k hàng) phải mất khoảng 60 giây.

Cách tiếp cận thứ hai của tôi là sử dụng CJ từ data.table và sau đó stri_detect_fixed trên 2 cột. Cách tiếp cận này là nhanh hơn (16 giây) nhưng tôi sợ rằng với dữ liệu ngày càng tăng, nó sẽ không thể sử dụng (nó làm tăng đáng kể việc sử dụng ram).

Tôi cũng đã cố gắng làm điều đó trong vòng lặp nhưng nó là chậm nhất.

Có cách nào để thực hiện nhanh hơn đặc biệt là trong dữ liệu.

Dưới đây tôi dán ví dụ của tôi:

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

Trên máy tính của tôi, mã sqldf ở trên mất 89,02 giây và mất 69,06 giây bằng cách sử dụng 'on instr (a.col1, b.col2)' thay vì 'trên ... như ...' và 409,35 giây với dữ liệu. bàn. Có một cuộc gọi 'thư viện (stringi)' bị thiếu. –

+0

Kết quả của các ví dụ của bạn khác nhau. Có lẽ bạn nên đưa ra một ví dụ đơn giản và giải thích những gì bạn muốn xảy ra trong các trường hợp góc. (Giá trị trong col1 không khớp, giá trị trong col2 không phù hợp và khả năng khớp nhiều) Ngoài ra, sẽ hữu ích khi biết nếu có một số ràng buộc về giá trị. – bluefish

+0

Tôi kiểm tra nó bằng 'instr' nhưng nó chậm hơn so với' on ... like ... '. Bây giờ tôi thêm thư viện và thay đổi bên trái tham gia để tham gia bên trong để làm cho kết quả giống nhau. – Kacper

Trả lời

1

Cách tiếp cận sqldf là nhanh nhất trên máy tính của tôi cho dữ liệu ví dụ của bạn, nhưng đây là một data.table phiên bản nhanh hơn trong trường hợp nó giúp.

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

Tôi đang chạy tính năng này trên OSX - bạn có thể cần phải tinh chỉnh mã song song cho các hệ điều hành khác. Ngoài ra, nếu dữ liệu thực tế của bạn lớn hơn và bạn sắp hết bộ nhớ, bạn có thể thử các giá trị batches lớn hơn.

Các vấn đề liên quan