是否有一种方法可以计算字符串的一般“相似度得分”?在某种程度上,我不是将两个字符串比较在一起,而是为每个字符串得到一些数字(哈希),以后可以告诉我两个字符串是否相似。两个相似的字符串应该具有相似(近距离)的哈希值。
让我们将这些字符串和分数视为一个例子:
Hello world 1000
Hello world! 1010
Hello earth 1125
Foo bar 3250
FooBarbar 3750
Foo Bar! 3300
Foo world! 2350
你可以看到 Hello world!和 Hello world 是相似的,他们的分数相互接近。
这样,找到与给定字符串最相似的字符串将通过从其他分数中减去给定字符串得分然后对其绝对值进行排序来完成。
答案 0 :(得分:23)
我相信你所寻找的是Locality Sensitive Hash。虽然大多数散列算法的设计使得输入的微小变化导致输出的大变化,但这些散列的尝试恰恰相反:输入的微小变化会产生相对较小的输出变化。
正如其他人所提到的,将多维映射强制转换为二维映射存在固有问题。它类似于创建地球的平面地图......你永远无法准确地在平面上表示球体。你能做的最好就是找到一个LSH,它针对你用来确定字符串是否“相似”的任何特性进行了优化。
答案 1 :(得分:11)
通常,这是不可能的,因为字符串之间的编辑距离集形成metric space,而不是具有固定维度的编辑距离。这意味着您无法在字符串和整数之间提供映射,以保留它们之间的距离度量。
例如,您无法为这三个短语分配数字:
这样数字反映了所有三个短语之间的差异。
答案 2 :(得分:11)
Levenstein距离或其衍生物是您想要的算法。 将给定字符串与字典中的每个字符串匹配。 (这里,如果你只需要固定数量的最相似的字符串,你可能想要使用min-heap。) 如果在字典中为所有字符串运行Levenstein距离太贵,那么使用一些粗略的 算法首先将从候选列表中排除太远的单词。 在那之后,对左候选人运行levenstein距离。
删除远程单词的一种方法是索引n-gram。 通过将每个单词拆分为n-gram列表来预处理字典。 例如,考虑n = 3:
(0) "Hello world" -> ["Hel", "ell", "llo", "lo ", "o w", " wo", "wor", "orl", "rld"]
(1) "FooBarbar" -> ["Foo", "ooB", "oBa", "Bar", "arb", "rba", "bar"]
(2) "Foo world!" -> ["Foo", "oo ", "o w", " wo", "wor", "orl", "rld", "ld!"]
接下来,创建n-gramms的索引:
" wo" -> [0, 2]
"Bar" -> [1]
"Foo" -> [1, 2]
"Hel" -> [0]
"arb" -> [1]
"bar" -> [1]
"ell" -> [0]
"ld!" -> [2]
"llo" -> [0]
"lo " -> [0]
"o w" -> [0, 2]
"oBa" -> [1]
"oo " -> [2]
"ooB" -> [1]
"orl" -> [0, 2]
"rba" -> [1]
"rld" -> [0, 2]
"wor" -> [0, 2]
当您需要为给定字符串找到最相似的字符串时,将给定字符串拆分为n-gram并仅选择那些字符串 字典中至少有一个匹配的n-gram的单词。 这会将候选人数量减少到合理数量,并且您可以使用levenstein匹配给每个左候选人的字符串。
如果字符串足够长,可以使用min-hashing technnique减小索引大小: 你计算每个n-gram的普通哈希值,并且只使用K个最小的哈希值,其他的则被丢弃。
P.S。 this presentation似乎是对您的问题的一个很好的介绍。
答案 3 :(得分:4)
虽然这个想法看起来非常甜蜜......我从来没有听说过这个。
我已经阅读了许多关于拼写纠正/拼写错误校正的许多,很多,技术,论文和科学论文,最快的建议围绕着索引和levenshtein距离。
有相当精细的技术,我目前正在研究的技术组合:
即使这并不意味着“不可能”获得分数,但我不知道如果这种“得分”方法被证明有效,那么最近对字符串比较的研究就不会那么多了。
如果你找到这样的方法,我非常感兴趣:)
答案 4 :(得分:2)
Levenshtein distance会为你效力吗?
答案 5 :(得分:2)
在一个无限问题中,没有解决方案可以将任何可能的单词序列或任何可能的字符序列转换为描述位置的单个数字。
想象一下角色级别的相似性
stops
spots
hello world
world hello
在两个示例中,消息都不同,但消息中的字符是相同的,因此度量需要保存位置值以及字符值。 (char 0 ==' h',char 1 ==' e' ...)
然后比较以下类似的消息
hello world
ello world
尽管两个字符串相似,但它们在开头或结尾处可能不同,这会使按位置缩放成为问题。
在
的情况下spots
stops
单词的位置只有不同,所以某种形式的位置很重要。
如果以下字符串相似
yesssssssssssssss
yessssssssssssss
然后你有一种形式的悖论。如果向第二个字符串添加2个s
个字符,它应该与第一个字符串共享它的距离,但它应该是不同的。这可以重复逐渐变长的字符串,所有这些字符串都需要靠近字符串,比它们更短更长。我无法看到如何实现这一目标。
一般来说,这被视为一个多维问题 - 将字符串分解为向量
[ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' ]
但是矢量的值不能是
如果单词的数量或字符串的长度有限,则可能有编码解决方案。
使用算术压缩之类的东西,然后可以将一系列单词转换为表示序列的浮点数。但是,这会将序列中较早的项目视为比序列中的最后一项更重要。
如果您接受问题是高维度的,那么您可以将字符串存储在度量标准树wikipedia : metric tree中。这会限制您的搜索空间,同时不会解决您的单个号码"溶液
有代码靠近在一起的物品应该一起存放在树的一部分中,但实际上并不能保证。子树的半径用于修剪搜索空间。
这在sqlite扩展中用于执行相似性搜索,但是没有单个数字解决方案,它可以计算出多少个编辑将一个字符串更改为另一个字符串。然后,这会得到一个得分相似的分数。
答案 6 :(得分:1)
您的想法听起来像ontology但适用于整个短语。两个短语越相似,它们越接近(假设您使用加权边)。反之亦然:非相似的短语彼此相距甚远。
另一种方法是使用傅立叶变换来获得给定字符串的'索引'(它不是单个数字,但总是如此)。您可以在this paper中找到更多内容。
另一个想法,基于Levenshtein距离:你可以比较n-gram,它会给你两个给定短语的相似性指数 - 它们越相似,它越接近1.这可以用来计算图中的距离。几年前写了一篇论文,如果你愿意我可以分享它。
无论如何:尽管我不知道确切的解决方案,但我也对你想出的内容感兴趣。
答案 7 :(得分:1)
答案 8 :(得分:0)
我想到这样的事情:
答案 9 :(得分:0)
不可能从两个短语中得到一个相当小的数字,这两个短语被比较,提供了他们的初始短语相似性的相关指示。
一个原因是这个数字在一个维度上给出了指示,而短语则在两个维度上发展,长度和强度。
这个数字的长度和强度一样长,但我不确定它会有多大帮助。
在二维中,你最好看一个矩阵,其中一些属性如 determinant (矩阵的一种导数)可以粗略地概括短语 trend
答案 10 :(得分:0)
在自然语言处理中,我们会调用最小编辑距离(也称为Levenshtein距离)
它基本上定义为将string1转换为string2所需的最小操作量
操作包括插入,删除,分配,每个操作都会给出一个分数,您可以将其添加到距离
解决问题的想法是从您选择的字符串计算MED,到所有其他字符串,对该集合进行排序并选出第n个第一个最小距离字符串
例如:
{"Hello World", "Hello World!", "Hello Earth"}
Choosing base-string="Hello World"
Med(base-string, "Hello World!") = 1
Med(base-string, "Hello Earth") = 8
1st closest string is "Hello World!"
这有点给你的字符串集合的每个字符串得分 C#实现(Add-1,Deletion-1,Subsitution-2)
public static int Distance(string s1, string s2)
{
int[,] matrix = new int[s1.Length + 1, s2.Length + 1];
for (int i = 0; i <= s1.Length; i++)
matrix[i, 0] = i;
for (int i = 0; i <= s2.Length; i++)
matrix[0, i] = i;
for (int i = 1; i <= s1.Length; i++)
{
for (int j = 1; j <= s2.Length; j++)
{
int value1 = matrix[i - 1, j] + 1;
int value2 = matrix[i, j - 1] + 1;
int value3 = matrix[i - 1, j - 1] + ((s1[i - 1] == s2[j - 1]) ? 0 : 2);
matrix[i, j] = Math.Min(value1, Math.Min(value2, value3));
}
}
return matrix[s1.Length, s2.Length];
}
复杂度 O(n x m)其中n,m是每个字符串的长度
有关最小编辑距离的更多信息,请参见here
答案 11 :(得分:-2)
好吧,你可以加上每个字符的ascii值,然后比较得分,它们可以有不同的最大值。但这并不保证它们会相似,因为两个不同的字符串可以具有相同的哈希值。
你当然可以制作一个更复杂的功能,首先检查字符串的大小,然后逐个比较每个字符,再次设置最大差值。