2016-03-15 2 views
11

Я ищу эффективный способ объединить 2 data.frames/data.tables на столбе персонажа, используя условие grep/like/stri_detect.R join on like/grep condition

Я могу использовать пакет sqldf с объединением на подобном, но довольно медленный. На моих 2 data.tables (5k строк, 20k строк) это занимает около 60 секунд.

Мой второй подход состоял в том, чтобы использовать CJ из data.table и после этого stri_detect_fixed на 2 столбцах. Этот подход выполняется быстрее (16 секунд), но я боюсь, что с ростом данных его невозможно будет использовать (это значительно увеличивает использование ПЗУ).

Я также пытался сделать это в цикле, но он был самым медленным.

Есть ли способ сделать это быстрее, особенно в 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 секунды, занял 69,06 секунды, используя 'on instr (a.col1, b.col2)' вместо 'on ... like ...' и 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.