我有一个" X"名字的数量,我需要将这些名称与另一个文件相匹配,看看这些名字是否在其中,但是以不同的方式书写(" Verizon" - >" Verizon LTD&#34 ;)
我正在使用"模糊查找"在视觉工作室2008上互操作,并取得了不错的成绩。
现在我尝试实现LevenshteinDistance方法来实现此结果,以便该方法使用完整列表迭代我需要的另一个文件的名称,并返回具有最佳分数/概率的名称是一样的。
我使用的代码如下:
public static int LevenshteinDistance(string src, string dest)
{
int[,] d = new int[src.Length + 1, dest.Length + 1];
int i, j, cost;
for (i = 0; i <= src.Length; i++)
{
d[i, 0] = i;
}
for (j = 0; j <= dest.Length; j++)
{
d[0, j] = j;
}
for (i = 1; i <= src.Length; i++)
{
for (j = 1; j <= dest.Length; j++)
{
if (src[i - 1] == dest[j - 1])
cost = 0;
else
cost = 1;
d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
}
}
return d[src.Length, dest.Length];
}
public static List<string> Search(string word, List<string> wordList, double fuzzyness)
{
List<string> foundWords = new List<string>();
foreach (string s in wordList)
{
// Calculate the Levenshtein-distance:
int levenshteinDistance =
LevenshteinDistance(word.ToUpper(), s.ToUpper());
// Length of the longer string:
int length = Math.Max(word.Length, s.Length);
// Calculate the score:
double score = 1.0 - (double)levenshteinDistance / length;
// Match?
if (score >= fuzzyness)
{
foundWords.Add(s);
}
}
return foundWords;
}
以下示例是我运行的测试,其中我们想要匹配的单词是&#34; ILCA INC&#34;,我们按如下方式运行:
相似度设置:&gt; = 0.77
搜索字词列表 &#34; ILCA&#34; 0.5 aprox - &gt;这是我们使用VS2008&#34;模糊查找&#34;得到的结果。 &#34; ICE INC&#34; 0.77 aprox - &gt;这是我的代码带来的。
如果我可以就此主题获得任何意见,我会非常感激,但是我无法让这个应用程序达到相同的结果,即模糊查找&#34;模糊查找&#34;确实
如果我能提供更多信息,或者我的问题表达错误,请告诉我。
答案 0 :(得分:0)
根据结果,微软的模糊搜索结果并不像1 - EditDistance / WordLength
那么简单。 “ILCA INC”和“ICE INC”之间的编辑距离是2 - 一次插入和一次替换。与Microsoft的模糊查找返回的更好结果相比,编辑的次数更少。
虽然模糊查找可能使用编辑距离作为其等式的部分,但我假设确定匹配分数的整体方法是专有的,本质上是算法和启发式的。正如您可能已经知道的那样,模糊查找优先考虑具有从0开始的子字符串匹配的单词,而不是具有较低编辑距离的单词。
答案 1 :(得分:0)
编写一个调试例程来转储d数组的内容非常方便,这样你就可以确保它的工作原理。例如,您提到的比较:
I C E I N C
0 1 2 3 4 5 6 7
I 1 0 1 2 3 4 5 6
L 2 1 1 2 3 4 5 6
C 3 2 1 2 3 4 5 5
A 4 3 2 2 3 4 5 6
5 4 3 3 2 3 4 5
I 6 5 4 4 3 2 3 4
N 7 6 5 5 4 3 2 3
C 8 7 6 6 5 4 3 2
正如另一张海报所提到的,2的距离是正确的,你的比较中有2个拼写错误(A的L和E都下降了)。得分为0.75,我不确定你是怎么得到的.77。
我愿意打赌微软算法正在以不同方式计算得分。它可能取两个长度的最小值或平均值而不是最大值,就像你一样。
计算正确百分比&#39;使用Levenshtein等算法是一个难题。正如您在示例中所看到的,短字符串比较产生百分比的狂野波动,并且使用适用于更长时间比较的阈值并不适用于较短的(反之亦然)。
阈值斜坡: 无论输入字符串长度如何,您当前的决策逻辑都使用常量值。但是,使用&#39; ramp&#39;有时更实际,其中over / under值根据字符串长度而变化。例如,您可能认为三个字符以下的字符串必须完全匹配(100%),四个字符串必须匹配超过70%,五个字符字符串为75%,六个为80%等。在某些时候(大约8-之后) 10个字符),通常可以坚持使用单个值。
实现非常简单,使用int []查找表:
double[] thresholds=new double[] {100, 100, 100, 70, 75, 80, (etc) };
double targetThreshold=thresholds[Math.Max(src.Length,dest.Length)-1];
...
if (score >= targetThreshold)
foundWords.Add(s);
(使用适合您需要的阈值)。它通常会带来更实际的结果。
这种技术的缺点是,如果你想要一个真正可变的阈值百分比,很难编码。正如您在我的示例中所看到的,我忽略了模糊度输入参数。