簡體   English   中英

在R中-最快的成對比較字符串相似性的方法

[英]In R - fastest way pairwise comparing character strings on similarity

我正在尋找一種加快以下方法的方法。 任何指針都非常歡迎。 瓶頸在哪里?

說我有以下data.frame

df <- data.frame(names=c("A ADAM", "S BEAN", "A APPLE", "J BOND", "J BOND"), 
                      v1=c("Test_a", "Test_b", "Test_a", "Test_b", "Test_b"), 
                      v2=c("Test_c", "Test_c", "Test_d", "Test_d", "Test_d"))

我想比較df中JaroWinkler相似度的每一對行。

在其他人的幫助下( 請參閱本文 ),我已經能夠構造以下代碼:

#columns to compare 
testCols <- c("names", "v1", "v2")

#compare pairs
RowCompare= function(x){
 comp <- NULL
 pairs <- t(combn(nrow(x),2))
 for(i in 1:nrow(pairs)){
   row_a <- pairs[i,1]
   row_b <- pairs[i,2]
   a_tests <- x[row_a,testCols]
   b_tests <- x[row_b,testCols]
 comp <- rbind(comp, c(row_a, row_b, TestsCompare(a_tests, b_tests)))
 }

colnames(comp) <- c("row_a","row_b","names_j","v1_j","v2_j")
return(comp)
}

#define TestsCompare
TestsCompare=function(x,y){
names_j <- stringdist(x$names, y$names, method = "jw")
v1_j <-stringdist(x$v1, y$v1, method = "jw")
v2_j <-stringdist(x$v2, y$v2, method = "jw")
c(names_j,v1_j, v2_j)
}

這將生成正確的輸出:

output = as.data.frame(RowCompare(df))

> output
   row_a row_b   names_j      v1_j      v2_j
1      1     2 0.4444444 0.1111111 0.0000000
2      1     3 0.3571429 0.0000000 0.1111111
3      1     4 0.4444444 0.1111111 0.1111111
4      1     5 0.4444444 0.1111111 0.1111111  
5      2     3 0.4603175 0.1111111 0.1111111
6      2     4 0.3333333 0.0000000 0.1111111
7      2     5 0.3333333 0.0000000 0.1111111
8      3     4 0.5634921 0.1111111 0.0000000
9      3     5 0.5634921 0.1111111 0.0000000
10     4     5 0.0000000 0.0000000 0.0000000

但是,我的實際data.frame有800萬觀察值,我進行了17次比較。 要運行此代碼需要幾天的時間...

我正在尋找加快此過程的方法:

  • 我應該使用矩陣而不是data.frames嗎?
  • 如何並行化此過程?
  • 向量化?

如果遍歷要檢查的變量,則可以使用stringdist::stringdistmatrix為每個變量創建距離矩陣。 使用lapplypurrr::map的形式將返回距離矩陣的列表(每列一個),您可以依次迭代到cal broom::tidy ,它將把它們轉換為格式良好的data.frames。 如果使用purrr::map_df並使用其.id參數,結果將被強制轉換為一個大的data.frame,並且每個列表元素的名稱將作為新列添加,因此您可以使它們保持直線。 生成的data.frame將采用長格式,因此如果您希望它與上面的結果匹配,請使用tidyr::spread重塑。

如注釋中所述,如果要對不同的變量使用不同的方法,請與map2Map並行進行迭代。

共,

library(tidyverse)

map2(df, c('soundex', 'jw', 'jw'), ~stringdist::stringdistmatrix(.x, method = .y)) %>% 
    map_df(broom::tidy, .id = 'var') %>% 
    spread(var, distance)

##    item1 item2 names        v1        v2
## 1      2     1     1 0.1111111 0.0000000
## 2      3     1     1 0.0000000 0.1111111
## 3      3     2     1 0.1111111 0.1111111
## 4      4     1     1 0.1111111 0.1111111
## 5      4     2     1 0.0000000 0.1111111
## 6      4     3     1 0.1111111 0.0000000
## 7      5     1     1 0.1111111 0.1111111
## 8      5     2     1 0.0000000 0.1111111
## 9      5     3     1 0.1111111 0.0000000
## 10     5     4     0 0.0000000 0.0000000

請注意,盡管select(5,2 choose(5, 2)返回10個觀測值,而select(8000000,2 choose(8000000, 2)返回3.2e + 13(32 萬億 )個觀測值,所以出於實際目的,即使它比現有代碼(和stringdistmatrix在可能的情況下進行一些並行化操作),除非您僅在子集上工作,否則數據將變得過大。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM