【问题标题】:R: producing a list of near matches with stringdist and stringdistmatrixR:使用 stringdist 和 stringdistmatrix 生成近似匹配列表
【发布时间】:2015-10-07 19:54:24
【问题描述】:

我发现了优秀的包“stringdist”,现在想用它来计算字符串距离。特别是我有一组单词,我想打印出近似匹配,其中“近似匹配”是通过一些算法,如 Levenshtein 距离。

我在 shell 脚本中的工作代码非常慢,我能够在 stringdist 中加载并生成一个带有度量的矩阵。现在我想将该矩阵归结为一个较小的矩阵,该矩阵只有近似匹配,例如其中指标不为零,但小于某个阈值。

kp <-  c('leaflet','leafletr','lego','levenshtein-distance','logo')
kpm <- stringdistmatrix(kp,useNames="strings",method="lv")
> kpm
                     leaflet leafletr lego levenshtein-distance
leafletr                   1                                   
lego                       5        6                          
levenshtein-distance      16       16   18                     
logo                       6        7    1                   19
m = as.matrix(kpm)
close = apply(m, 1, function(x) x>0 & x<5)
>  close
                     leaflet leafletr  lego levenshtein-distance  logo
 leaflet                FALSE     TRUE FALSE                FALSE FALSE
 leafletr                TRUE    FALSE FALSE                FALSE FALSE
 lego                   FALSE    FALSE FALSE                FALSE  TRUE
 levenshtein-distance   FALSE    FALSE FALSE                FALSE FALSE
 logo                   FALSE    FALSE  TRUE                FALSE FALSE

好的,现在我有一个(大)dist,我如何将它减少到一个输出类似于的列表

leafletr,leaflet,1
logo,lego,1

仅适用于指标非零且小于 n=5 的情况?我找到了“apply()”,它可以让我做测试,现在我需要弄清楚如何使用它。

问题不是特定于 stringdist 和 stringdistmatrix 并且是非常基本的 R,但我仍然被卡住了。我怀疑答案涉及subset(),但我不知道如何将“dist”转换为其他内容。

【问题讨论】:

  • 如果您能向我们展示kpm 或“您的大矩阵”将会很有帮助,这样我们就知道您在使用什么。或者,您可以通过提供一些虚拟数据或真实数据dput(head(read.table("..."),20)) 并将其包含在问题中来使您的问题可重现。
  • 谢谢 Brandon,会的,我将缩减为 5x5 矩阵并包含所有代码。正在使用 100 大小的原件。

标签: r string matrix stringdist


【解决方案1】:

设置您的数据:

library('stringdist')
library('dplyr')
kp <-  c('leaflet','leafletr','lego','levenshtein-distance','logo')
kpm <- stringdistmatrix(kp,useNames="strings",method="lv")

在这里我们可以将kpm 更改为数据框:

kpm <- data.frame(as.matrix(kpm))

这是一种获取具有“1”的数据框以标记单词足够接近的位置的方法:

idx <- apply(kpm, 2, function(x) x >0 & x<5)
idx <- apply(idx, 1:2, function(x) if(isTRUE(x)) x<-1 else x<-NA)
#> idx
#                     leaflet leafletr lego levenshtein.distance logo
#  leaflet                   NA        1   NA                   NA   NA
#  leafletr                   1       NA   NA                   NA   NA
#  lego                      NA       NA   NA                   NA    1
#  levenshtein-distance      NA       NA   NA                   NA   NA
#  logo                      NA       NA    1                   NA   NA

为了简单起见,融化数据框,过滤它并去掉最后一列:

final <- melt(idx) %>%
        filter(value==1) %>%
        select(Var1, Var2)

别忘了把所有东西都变成字符,而不是因子! (有时就像 R 中的破纪录一样......)

final[] <- lapply(final, as.character)
#> final
#      Var1     Var2
#  leafletr  leaflet
#   leaflet leafletr
#      logo     lego
#      lego     logo

现在我们摆脱重复:

final <- final[!duplicated(data.frame(list(do.call(pmin,final),do.call(pmax,final)))),]

加上一些好名字,你就可以开始了。

names(final) <- c('string 1', 'string 2')
#> final
# string 1 string 2
# leafletr  leaflet
#     logo     lego

(虽然您请求了一个列表,但这是一个数据框。从这里可以很容易地根据您的需要转换为您想要的任何内容,例如,写入 csv 等)

【讨论】:

    【解决方案2】:

    你可以这样做:

    library(reshape2)
    d <- unique(melt(m))
    out <- subset(d, value > 0 & value < 5)
    

    这里,meltm 转换为长格式(2 列带有字符串名称,1 列带有值)。但是,由于我们已经融合了一个对称矩阵,所以我们使用unique 进行重复数据删除。

    另一种方法是使用dplyr(因为现在所有酷孩子都在使用带有管道的dplyr):

    library(dlpyr)
    library(reshape2)
    library(magrittr)
    
    out <- melt(m) %>% distinct() %>% filter(value > 0 & value < 5)
    

    第二个选项可能更快,但我还没有真正计时。

    【讨论】:

    • 哦,如果你做了 melt(m, as.is=TRUE) m 的标签不会被转换成因子。
    • 我的工具箱里没有melt(),谢谢,这很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-17
    • 2015-02-12
    • 2015-10-28
    • 1970-01-01
    • 2016-03-11
    • 2013-04-15
    相关资源
    最近更新 更多