我尝试使用n-gram来为列表中的每个字符串找到最相似的字符串,目前我有这个字符串向量
let arr = [
"Bilbo Baggins",
"Gandalf",
"Thorin",
"Balin",
"Kili",
"Fili",
"John",
"Frodo Baggins",
]
使用下面的代码,我为每个字符串创建二元模型,并将它们存储在一个向量中:
let arr = [
"Bilbo Baggins",
"Gandalf",
"Thorin",
"Balin",
"Kili",
"Fili",
"John",
"Frodo Baggins",
]
.iter()
.map(|elem|
elem
.len()
.rem(2)
.ne(&0)
.then_some(format!("{elem} "))
.unwrap_or(elem.to_string())
)
.map(|elem| elem.chars().array_chunks().collect::<Vec<[char; 2]>>())
.collect::<Vec<_>>();
输出量:
[['B', 'i'], ['l', 'b'], ['o', ' '], ['B', 'a'], ['g', 'g'], ['i', 'n'], ['s', ' ']]
[['G', 'a'], ['n', 'd'], ['a', 'l'], ['f', ' ']]
[['T', 'h'], ['o', 'r'], ['i', 'n']]
[['B', 'a'], ['l', 'i'], ['n', ' ']]
[['K', 'i'], ['l', 'i']]
[['F', 'i'], ['l', 'i']]
[['J', 'o'], ['h', 'n']]
[['F', 'r'], ['o', 'd'], ['o', ' '], ['B', 'a'], ['g', 'g'], ['i', 'n'], ['s', ' ']]
问题是,我如何将某种集合逻辑应用于这些二元模型向量,以找到每个字符串最相似的字符串,并得到以下输出?
'Bilbo Baggins' most similar string: 'Frodo Baggins'
'Gandalf' most similar string: None
'Thoring' most similar string: 'Balin'
'Balin' most similar string: 'Thorin'
'Kili' most similar string: 'Fili'
'Fili' most similar string: 'Kili'
'John' most similar string: None
'Frodo Baggins' most similar string: 'Bilbo Baggins'
1条答案
按热度按时间5n0oy7gb1#
有很多不同的算法可以用来计算字符串之间的距离。你正在寻找的bigram的算法可能是cosine similarity函数。它可以用来迭代bigram并计算一个值来表示两个向量(或者字符串,在这个例子中)之间的相似性。它似乎更倾向于匹配更长的字符串,因为它们之间有更多的重复字符组。
下面是通过余弦相似度查找最接近的名称的示例:
第一个
Balin
看起来并不完全正确,因为余弦距离没有考虑字符串长度。另一种流行的方法是求Levenshtein distance(我使用Wagner Fischer algorithm来计算它),它是将一个字符串转换为另一个字符串所需的插入、删除或替换的次数第一次
Balin
仍然不是你想要的,因为它只需要最少的修改就可以得到Kili
,但是它看起来确实更接近了。希望这能帮助你更接近你想要的,但是你可能需要使用算法的组合,或者如果你想让Balin 匹配Thorin,找到一个对单词的开头/结尾加权不同的算法。