R присоединяется к условию типа/grep

Я ищу эффективный способ объединить 2 data.frames/data.tables в столбец символов, используя условие grep/like/stri_detect.

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

Мой второй подход заключался в использовании CJ из data.table и после этого stri_detect_fixed на 2 столбцах. Этот подход выполняется быстрее (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)])

Ответ 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.