前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Jaro-Winkler Distance JAVA代码实现版

Jaro-Winkler Distance JAVA代码实现版

作者头像
wust小吴
发布2022-03-07 14:25:06
4250
发布2022-03-07 14:25:06
举报
文章被收录于专栏:风吹杨柳风吹杨柳

接口:

代码语言:javascript
复制
public interface StringDistance {
	
	public float getDistance(String s1, String s2) ;

}

方法类:

代码语言:javascript
复制
public class JaroWinklerDistance implements StringDistance {

	private float threshold = 0.7f;

	private int[] matches(String s1, String s2) {

		String max, min;
		if (s1.length() > s2.length()) {

			max = s1;
			min = s2;

		} else {

			max = s2;
			min = s1;

		}
		int range = Math.max(max.length() / 2 - 1, 0);
		int[] matchIndexes = new int[min.length()];
		Arrays.fill(matchIndexes, -1);
		boolean[] matchFlags = new boolean[max.length()];
		int matches = 0;
		for (int mi = 0; mi < min.length(); mi++) {

			char c1 = min.charAt(mi);
			for (int xi = Math.max(mi - range, 0), xn = Math.min(
					mi + range + 1, max.length()); xi < xn; xi++) {

				if (!matchFlags[xi] && c1 == max.charAt(xi)) {

					matchIndexes[mi] = xi;
					matchFlags[xi] = true;
					matches++;
					break;

				}

			}

		}
		char[] ms1 = new char[matches];
		char[] ms2 = new char[matches];
		for (int i = 0, si = 0; i < min.length(); i++) {

			if (matchIndexes[i] != -1) {

				ms1[si] = min.charAt(i);
				si++;

			}

		}
		for (int i = 0, si = 0; i < max.length(); i++) {

			if (matchFlags[i]) {

				ms2[si] = max.charAt(i);
				si++;

			}

		}
		int transpositions = 0;
		for (int mi = 0; mi < ms1.length; mi++) {

			if (ms1[mi] != ms2[mi]) {

				transpositions++;

			}

		}
		int prefix = 0;
		for (int mi = 0; mi < min.length(); mi++) {

			if (s1.charAt(mi) == s2.charAt(mi)) {

				prefix++;

			} else {

				break;

			}

		}
		return new int[] { matches, transpositions / 2, prefix, max.length() };

	}

	public float getDistance(String s1, String s2) {

		int[] mtp = matches(s1, s2);
		float m = (float) mtp[0];
		if (m == 0) {

			return 0f;

		}
		float j = ((m / s1.length() + m / s2.length() + (m - mtp[1]) / m)) / 3;
		float jw = j < getThreshold() ? j : j + Math.min(0.1f, 1f / mtp[3])
				* mtp[2] * (1 - j);
		return jw;

	}

	/**
	 * Sets the threshold used to determine when Winkler bonus should be used.
	 * Set to a negative value to get the Jaro distance.
	 * 
	 * @param threshold
	 *            the new value of the threshold
	 */
	public void setThreshold(float threshold) {

		this.threshold = threshold;

	}

	/**
	 * Returns the current value of the threshold used for adding the Winkler
	 * bonus. The default value is 0.7.
	 * 
	 * @return the current value of the threshold
	 */
	public float getThreshold() {

		return threshold;

	}
}

当然你也可以直接使用jar插件的方法

该方法的api地址:

http://lucene.apache.org/core/3_0_3/api/contrib-spellchecker/org/apache/lucene/search/spell/JaroWinklerDistance.html

http://lucene.apache.org/core/3_0_3/api/contrib-spellchecker/org/apache/lucene/search/spell/StringDistance.html

Jaro-Winkler Distance 算法

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

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

m是匹配的字符数;

t是换位的数目。

两个分别来自S1和S2的字符如果相距不超过

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

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

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

dj是两个字符串的Jaro Distance

是前缀的相同的长度,但是规定最大为4

p则是调整分数的常数,规定不能超过0.25,不然可能出现dw大于1的情况,Winkler将这个常数定义为0.1

这样,上面提及的MARTHA和MARHTA的Jaro-Winkler Distance为:

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

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档