Jaro-Winkler Distance 浅析

来源:互联网 发布:算法统宗歌诀歌诀 编辑:程序博客网 时间:2024/04/28 01:07

这是一种计算两个字符串之间相似度的方法,想必都听过Edit Distance,Jaro-Winkler Distance 是Jaro Distance的一个扩展,而Jaro Distance(Jaro 1989;1995)据说是用来判定健康记录上两个名字是否相同,也有说是是用于人口普查,具体干什么就不管了,让我们先来看一下Jaro Distance的定义。

两个给定字符串S1和S2的Jaro Distance为:

 

image

  • m是匹配的字符数;
  • t是换位的数目。

两个分别来自S1和S2的字符如果相距不超过  image     时,我们就认为这两个字符串是匹配的;而这些相互匹配的字符则决定了换位的数目t,简单来说就是不同顺序的匹配字符的数目的一半即为换位的数目t,举例来说,MARTHAMARHTA的字符都是匹配的,但是这些匹配的字符中,T和H要换位才能把MARTHA变为MARHTA,那么T和H就是不同的顺序的匹配字符,t=2/2=1.

那么这两个字符串的Jaro Distance即为:

image 

而Jaro-Winkler则给予了起始部分就相同的字符串更高的分数,他定义了一个前缀p,给予两个字符串,如果前缀部分有长度为image 的部分相同,则Jaro-Winkler Distance为:

image

  • dj是两个字符串的Jaro Distance
  • image 是前缀的相同的长度,但是规定最大为4
  • p则是调整分数的常数,规定不能超过0.25,不然可能出现dw大于1的情况,Winkler将这个常数定义为0.1

这样,上面提及的MARTHAMARHTA的Jaro-Winkler Distance为:

dw = 0.944 + (3 * 0.1(1 − 0.944)) = 0.961

以上资料来源于维基百科:

http://en.wikipedia.org/wiki/Jaro-Winkler_distance

这样一来很容易写出这个算法的代码:

   1: double jaro_distance(string s1,string s2)
   2: {
   3:     if(s1.empty()||s2.empty())
   4:     {
   5:         if(s1.empty()&&s2.empty())
   6:             return 1.0;
   7:         return 0.0;
   8:     }
   9:     int allowrange=max(s1.length(),s2.length())/2-1;
  10:     int i,j;
  11:     bool is_match=false;
  12:     int *matches=new int[s2.length()];
  13:     //将s2中匹配的字符标号,这个标号的意义在于计算t的值,
  14:     //从前往后遍历,如果顺序不对,则肯定要调换
  15:     //DWAYEN
  16:     //0-132  这是一个matches的例子
  17:     //DUANE
  18:     for(i=0;i<s2.length();++i)
  19:         matches[i]=-1;
  20:     double m=0;//匹配的数目
  21:     for(i=0;i<s1.length();++i)
  22:     {
  23:         is_match=false;
  24:         for(j=i;is_match==false && j>=0 && j>=i-allowrange;--j)
  25:         {
  26:             if(s2[j]==s1[i])
  27:             {
  28:                 matches[j]=m++;
  29:                 is_match=true;
  30:             }
  31:         }
  32:         for(j=i;is_match==false && j<s2.length() && j<=i+allowrange;++j)
  33:         {
  34:             if(s2[j]==s1[i])
  35:             {
  36:                 matches[j]=m++;
  37:                 is_match=true;
  38:             }
  39:         }
  40:     }
  41:     double t=0;
  42:     i=0;
  43:     for(j=0;j<s2.length();++j)
  44:     {
  45:         if(matches[j]!=-1)
  46:         {
  47:             if(matches[j]!=i++)
  48:                 ++t;
  49:         }
  50:     }
  51:     delete []matches;
  52:     return (m/s1.length()+m/s2.length()+(m-t/2)/m)/3;
  53:  
  54: }
  55: double jaro_winkler_distance(string s1,string s2)
  56: {
  57:     int i;
  58:     double p=0.1;
  59:     int len=0;
  60:     for(i=0;i<4;++i)
  61:     {
  62:         if(s1[i]!=s2[i])
  63:             break;
  64:         ++len;
  65:     }
  66:     double dj=jaro_distance(s1,s2);
  67:     return dj+p*len*(1-dj);
  68: }
原创粉丝点击