在 R 中比较字符串列表

Compare a list of strings with each other in R

我正在尝试使用包 'RecordLinkage' 中的函数 levenshteinSim() 将字符串列表相互比较。但是,我很难弄清楚如何将我的字符串列表合并到函数中,因为它只需要两个参数 str1 和 str2。我试图找到最佳方式,因为我的列表包含 4k 字符串。任何帮助深表感谢!

下面是一些示例数据:

sample <- c('apple', 'appeal', 'apparel', 'peel', 'peer', 'pear')

所以,我认为这可能就是您想要的。 RecordLinkage 包不在 CRAN 上了,所以我去找了另一个计算 Levenshtein 距离的包:

library(stringdist)

sample <- c('apple', 'appeal', 'apparel', 'peel', 'peer', 'pear')

df <- expand.grid(sample, sample) # this creates a dataframe of all combinations of the sample elements

stringdist(df$Var1, df$Var2, method = "lv")

输出:

[1] 0 3 3 4 4 4 3 0 3 3 4 3 3 3 0 4 5 4 4 3 4 0 1 2 4 4 5 1 0 1 4 3 4 2 1 0

也许更有吸引力 - dplyr 版本:

library(dplyr)

df %>%
    mutate(levenshtein = stringdist(Var1, Var2, method = "lv"))

输出

     Var1  Var2 levenshtein
1   apple apple           0
2  appeal apple           3
3 apparel apple           3
4    peel apple           4
5    peer apple           4
6    pear apple           4
...

这里有一个base R的解法得到距离矩阵

z <- Map(utf8ToInt,sample)
dmat <- outer(z,z,FUN = Vectorize(function(x,y) sum(bitwXor(x,y)>0)))

这样

> dmat
        apple appeal apparel peel peer pear
apple       0      3       4    4    5    5
appeal      3      0       4    6    6    6
apparel     4      4       0    6    6    6
peel        4      6       6    0    1    2
peer        5      6       6    1    0    1
pear        5      6       6    2    1    0

在没有最近从 CRAN 中删除的 RecordLinkage 包的情况下,获得编辑距离或编辑相似度非常简单。

在基数 R 中:

sample <- c('apple', 'appeal', 'apparel', 'peel', 'peer', 'pear')
adist(sample)
#>      [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,]    0    3    3    4    4    4
#> [2,]    3    0    3    3    4    3
#> [3,]    3    3    0    4    5    4
#> [4,]    4    3    4    0    1    2
#> [5,]    4    4    5    1    0    1
#> [6,]    4    3    4    2    1    0

使用更快的 stringdist 包(它支持一系列替代方法来调整距离,检查 help("stringdist-metrics")

stringdist::stringdistmatrix(sample, method = "lv", useNames = "strings")
#>         apple appeal apparel peel peer
#> appeal      3                         
#> apparel     3      3                  
#> peel        4      3       4          
#> peer        4      4       5    1     
#> pear        4      3       4    2    1

如果你想要类似的字符串,你可以使用 stringsim()stringsimmatrix 来一次获取所有比较(目前仅在开发版本中可用;devtools::install_github("markvanderloo/stringdist/pkg")):

stringdist::stringsimmatrix(sample, method = "lv", useNames = "strings")
#>             apple    appeal apparel      peel      peer      pear
#> apple   1.0000000 0.4000000     0.4 0.2000000 0.2000000 0.2000000
#> appeal  0.5000000 1.0000000     0.5 0.5000000 0.3333333 0.5000000
#> apparel 0.5714286 0.5714286     1.0 0.4285714 0.2857143 0.4285714
#> peel    0.0000000 0.2500000     0.0 1.0000000 0.7500000 0.5000000
#> peer    0.0000000 0.0000000     0.0 0.7500000 1.0000000 0.7500000
#> pear    0.0000000 0.2500000     0.0 0.5000000 0.7500000 1.0000000

如果你想把它变成一个整洁的格式,你可以这样做:

library(tidyverse)
stringdist::stringsimmatrix(sample, method = "lv", useNames = "strings") %>% 
  as.matrix() %>%
  as_tibble(rownames = "word1") %>% 
  pivot_longer(-word1, names_to = "word2", values_to = "distance")
#> # A tibble: 36 x 3
#>    word1  word2   distance
#>    <chr>  <chr>      <dbl>
#>  1 apple  apple      1    
#>  2 apple  appeal     0.4  
#>  3 apple  apparel    0.4  
#>  4 apple  peel       0.200
#>  5 apple  peer       0.200
#>  6 apple  pear       0.200
#>  7 appeal apple      0.5  
#>  8 appeal appeal     1    
#>  9 appeal apparel    0.5  
#> 10 appeal peel       0.5  
#> # ... with 26 more rows