【问题标题】:String similarity for longer text (searching for words in sentences) in RR中较长文本的字符串相似度(搜索句子中的单词)
【发布时间】:2022-11-14 20:12:59
【问题描述】:

我需要找到一种计算有效的方法来识别和匹配句子中的单词。我知道有各种字符串相似度包,它们使用 Levenshtein 距离、Jaccard 距离、余弦等方法,如stringdist。但是这些在近似两个长度大致相同的字符串的相似度方面是有效的。基本上我必须将短字符串与长字符串进行比较。

我认为最好通过一个例子来说明,我有描述SPECIAL JOS VALEY CHOCK COOKIES 10X550GR,我想确定它是否属于JOE'S VALLEY品牌产品。例如,在这两个字符串之间进行 Levenshteins 相似性将产生较差的相似性。但是,如果我决定使用子字符串并仅使用 JOS VALEY 作为描述,则相似度得分会更高并且可以匹配。

library(stringdist)

# Decription we want to search
sku <- "SPECIAL JOS VALEY CHOCK COOKIES 10X550GR"
# An established brand in our database
br <- "JOE'S VALLEY"
# For comparison below, this is the misspelled brand in the actual description above
sku_br <- "JOS VALEY" 
# Similarity measures 
methods <- c("osa", "lv", "dl", "hamming", "lcs", "qgram", "cosine", "jaccard", "jw", "soundex")

# Test similarity scores methods
for(i in 1:length(methods)){
     cat(paste0(methods[i],":\n"))
     cat(paste0(sku," <-> ",br," ====> ",stringsim(sku,br,method = methods[i]),"\n"))
     cat(paste0(sku_br ," <-> ",br," ====> ",stringsim(sku_br,br,method = methods[i]),"\n"))
     cat(paste0("\n"))
 }

如果你不能运行上面的代码,这里是输出:

osa:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.175
JOS VALEY <-> JOE'S VALLEY ====> 0.75

lv:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.175
JOS VALEY <-> JOE'S VALLEY ====> 0.75

dl:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.175
JOS VALEY <-> JOE'S VALLEY ====> 0.75

hamming:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0
JOS VALEY <-> JOE'S VALLEY ====> 0

lcs:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.346153846153846
JOS VALEY <-> JOE'S VALLEY ====> 0.857142857142857

qgram:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.423076923076923
JOS VALEY <-> JOE'S VALLEY ====> 0.857142857142857

cosine:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.649519052838329
JOS VALEY <-> JOE'S VALLEY ====> 0.916666666666667

jaccard:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.428571428571429
JOS VALEY <-> JOE'S VALLEY ====> 0.9

jw:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0.624494949494949
JOS VALEY <-> JOE'S VALLEY ====> 0.805555555555555

soundex:
SPECIAL JOS VALEY CHOCK COOKIES 10X550GR <-> JOE'S VALLEY ====> 0
JOS VALEY <-> JOE'S VALLEY ====> 1

从上面的结果我们可以看出,完整的 sku 描述与比较品牌的匹配度并不高。但是,如果我们对拼写错误的品牌进行子串化,它会获得可接受的匹配分数。

所以我有一个解决方案是创建一个“搜索窗口”,它遍历整个完整描述(搜索窗口长度等于品牌字符串的长度)。例如,它将首先计算以下之间的相似性:

  1. SPECIAL JOS JOE'S VALLEY 然后如果分数小于容差,它会将窗口增加一个字符。
  2. PECIAL JOS V比较JOE'S VALLEY然后如果分数更少......
  3. ECIAL JOS VA比较JOE'S VALLEY然后如果分数更少... 直到它获得的分数超过所需的容差为止,它将返回一个匹配项。

    这在计算上非常昂贵,并且由于我们数据库中的品牌数量而加剧。所以我的问题是,有没有更有效的方法来做到这一点?

    感谢您阅读。

【问题讨论】:

    标签: r text text-mining similarity


    【解决方案1】:

    如果对常见的拼写错误有很好的了解,您可以使用正则表达式。例子:

    sku <- "SPECIAL JOS VALEY CHOCK COOKIES 10X550GR"
    joes_valley_regex <- "JOE?'?S\s+VALL?[EA]Y"
    
    grepl(joes_valley_regex,sku)
    

    【讨论】:

    • 好主意谢谢,我只是不知道在整个数据库(即品牌列表)上应用正则表达式是多么可行(以及它是否可持续发展)。
    猜你喜欢
    • 2013-06-22
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    相关资源
    最近更新 更多