将5000个字符串与PHP Levenshtein进行比较
我在一个数组中有5000个(有时更多)街道地址字符串。我想把它们和莱文施泰因进行比较,找出相似的匹配。我如何才能做到这一点,而不循环遍历所有5000个,并直接与其他4999个进行比较将5000个字符串与PHP Levenshtein进行比较,php,database,similarity,street-address,levenshtein-distance,Php,Database,Similarity,Street Address,Levenshtein Distance,我在一个数组中有5000个(有时更多)街道地址字符串。我想把它们和莱文施泰因进行比较,找出相似的匹配。我如何才能做到这一点,而不循环遍历所有5000个,并直接与其他4999个进行比较 编辑:如果有人提出建议,我也对其他方法感兴趣。总体目标是根据用户提交的街道地址查找类似的条目(并消除重复条目)。我认为您无法避免在数组中循环,因为levenstein()函数只接受字符串而不接受数组作为输入 您可以执行以下操作: for($i=0;$i<count($array)-1;$i++) {
编辑:如果有人提出建议,我也对其他方法感兴趣。总体目标是根据用户提交的街道地址查找类似的条目(并消除重复条目)。我认为您无法避免在数组中循环,因为levenstein()函数只接受字符串而不接受数组作为输入 您可以执行以下操作:
for($i=0;$i<count($array)-1;$i++)
{
for($j=$i+1;$j<count($array);$j++)
{
$lev = levenshtein($array[$i],$array[$j]);
if($lev == 0)
{
// exact match
}
else if($lev <= THRESHOLD)
{
// similar
}
}
}
for($i=0;$i由于Levenshtein算法的性质(特别是它是两个字符串之间的比较),我看不出这是怎么可能的
当然,您可以通过首先执行一些基本的匹配要求来减少比较次数,但这超出了您所要求的范围
作为一个(很可能是不相关的)选项,您可以始终使用类似于soundex
的东西,它可以让您预先计算字符串值。(我相信您也可以直接在MySQL中使用它。)您可以基于soundex对它们进行分组,然后将比较限制在最接近的N个情况下
$mashed=array();
foreach ($address as $key=>$val) {
$mashed[$key]=soundex($val);
}
sort($mashed);
然后遍历$mashed的键
C.考虑到您的问题,如果您想使用,我认为除了将每个地址与每个其他地址进行比较之外,没有其他方法
首先,你应该规范地址,去掉缩写等
- 大道->大道
- 路->路
对于类似的地址,您可以有一些固定的最大Lehvenstein距离(N)
如果是这样,您可以在确定当前地址对的编辑距离大于N时中止Lehvenstein算法。为此,您需要编写Lehvenstein算法的自定义版本。这将使该算法更快一些
还有一些相关的微不足道的优化。例如:如果地址A是10个字符长,地址B是20个字符长,那么你认为Levvestin距离小于8的地址是相似的。你可以查看地址的长度,并立即确定它们不相似。
< P>如果你想找到所有相似的值,你就可以。必须将所有项与所有其他项进行比较。但选择正确的数组函数将显著加快速度。下面是一个快速示例(结果数组可能更好):
您可以使用加速搜索/比较
说:
现在我们可以对Levenshtein距离做一个特别有用的观察:它形成一个度量空间。
[…]
假设我们有两个参数,query,我们在搜索中使用的字符串,n字符串与查询的最大距离,并且仍然可以返回。假设我们取一个任意字符串,测试并将其与查询进行比较。调用结果距离d。因为我们知道三角形不等式成立,所以我们所有的结果都必须具有最大距离d+n,且至少距离测试点d-n。
[…]
测试表明,距离为1的搜索查询不超过树的5-8%,两个错误的搜索查询不超过树的17-25%——与检查每个节点相比,这是一个显著的改进!
编辑:但这对你的(“12伯德路,6号公寓”和“12伯德路#6”)问题没有帮助。只有通过蛮力m*n比较。我认为对类似地址进行分组的更好方法是:
创建一个包含两个表的数据库-一个用于地址(和一个id),一个用于地址中单词或文字数字的音效(使用addresses表的外键)
大写地址,将[A-Z]或[0-9]以外的任何内容替换为空格
将地址按空格分割,计算每个“单词”的soundex,保留所有数字不变,并将其存储在soundexes表中,使用您开始使用的地址的外键
对于每个地址(id为$target),查找最相似的地址:
SELECT similar.id, similar.address, count(*)
FROM adress similar, word cmp, word src
WHERE src.address_id=$target
AND src.soundex=cmp.soundex
AND cmp.address_id=similar.id
ORDER BY count(*)
LIMIT $some_value;
计算源地址和查询返回的前几个值之间的levenstein差
(在数据库中,在大型数组上执行任何类型的操作通常都会更快)$stringA=“这是php编程语言”;
$stringB=“这是一个完整的编程脚本,java php和所有其他次要语言都包含在其中”;
回显“字符串1-->”。$stringA。“
”;
回显“字符串2-->”。$stringB。“
”;
//将字符串更改为数组
$array1=爆炸(“”,$stringA);
$array2=爆炸(“”,$stringB);
//从两个字符串中获取相同的元素
$c=数组相交($array1,$array2);
//将数组更改为字符串
$d=内爆(“”,$c);
回显“字符串相同元素-->”$d.“
”;
//从两个数组中获取difrent元素
$result=array_diff($array2,$array1);
//将数组更改为字符串
$zem=内爆(“”,$result);
如果(!空($zem)){
echo“字符串差异-->”$zem。“
”;
}否则{
echo“字符串差异-->两个字符串相同
”;
}
类似的文本($stringA,$d,$p);
echo“字符串之间的相似性为“$p.”%
”;
我从来没有使用过Soundex。你知道它们在街道地址类型缩写词“St.”中的作用有多好吗?Soundex()设计用于处理人名。如果你将它们应用于地址,则将Soundex算法应用于地址的每个部分是有意义的,例如“23 Bird Road”->Soundex(“Bird”)和Soundex(“Road”)此解决方案类似于O(2n)
或O(2nm)
(均未简化),其中m
是地址中的每个单词。这是对O(n^2)的极大改进
。它不能插入缩写-但St可以是Street或Saint或…?取决于上下文。C.我担心这会导致2500万次比较。@phirschybar:实际上它将是1250万次,我们只比较不同的
SELECT similar.id, similar.address, count(*)
FROM adress similar, word cmp, word src
WHERE src.address_id=$target
AND src.soundex=cmp.soundex
AND cmp.address_id=similar.id
ORDER BY count(*)
LIMIT $some_value;
$stringA = "this is php programming language";
$stringB = "this is complete programming script in which java php and all other minor languages include";
echo "string 1---->".$stringA."<br />";
echo "string 2---->".$stringB."<br />";
// changing string to arrays
$array1 = explode(' ', $stringA);
$array2 = explode(' ', $stringB);
// getting same element from two strings
$c = array_intersect($array1, $array2);
// changing array to the string
$d=implode(' ',$c);
echo "string same elements---> ".$d."<br />";
// getting difrent element from two arrays
$result = array_diff($array2, $array1);
// changing array to the string
$zem = implode(' ',$result);
if (!empty($zem)) {
echo "string diffrence---> ".$zem."<br />";
} else {
echo "string diffrence--->both strings are same <br />";
}
similar_text($stringA, $d, $p);
echo " similarity between the string is ".$p."% <br />";