同義詞相似度可以怎樣計算

超人汪小建發表於2018-06-28

前言

詞語的相似性的計算方法有很多,比如字面相似度計算方法、基於語義詞典的計算方法、基於統計的相似度(向量空間模型)計算方法和基於神經網路的相似度計算方法。

本篇文章講講基於詞林的語義相似性。

詞林

《同義詞詞林》是上世紀80年代出版的對漢語詞彙進行語義分類的義類詞典,共收錄64223條詞目。隨後發展,哈爾濱工業大學資訊檢索實驗室對其進行修正完善,《哈工大社會計算與資訊檢索研究中心同義詞詞林擴充套件版》。

格式

舉個例子一般的格式如下,一共包含了五個級別和一個標記位,看下面第一行從左到右,A為一級、a為二級、01為三級、A為四級、02為五級、=為標記位。標記位主要是用於區分常規同義詞、相關詞和只有詞語本身,分別用= # @三個符號表示。其中 = 表示常規同義詞,# 表示相關詞,@ 則表示獨立性質,既沒有同義詞也沒有相關詞。

Aa01A02= 人類 生人 全人類
Aa01B03# 良民 順民
Aa01D01@ 角色
Aa02A08= 奴 妾 妾身 民女
複製程式碼
編碼位 1 2 34 5 67 8
類別級別 一級 二級 三級 四級 五級 標記位
類別含義 大類 中類 小類 詞群 原子詞群 詞語關係

詞語相似度

詞林的格式可以看成是一共有6個級,那麼可以給每個級分配一定的權重,比如分配為 1.2, 1.2, 1.0, 1.0, 0.8, 0.4,總和為5.6。那麼計算相似度時其實就是先獲取兩個單詞對應的編碼,然後再逐一對比編碼每個級是否相等,將所有相等的級的權重加起來,除以總和得到的值即為相似性值。實現如下:

public static double sumWeight(String code1, String code2) {
		double weight = 0.0;
		for (int i = 1; i <= 6; i++) {
			String c1 = getLevelCode(code1, i);
			String c2 = getLevelCode(code2, i);
			if (c1.equals(c2)) {
				weight += WEIGHT[i - 1];
			} else {
				break;
			}
		}
		return weight;
	}

public static String getLevelCode(String code, int level) {
		switch (level) {
		case 1:
			return code.substring(0, 1);
		case 2:
			return code.substring(1, 2);
		case 3:
			return code.substring(2, 4);
		case 4:
			return code.substring(4, 5);
		case 5:
			return code.substring(5, 7);
		case 6:
			return code.substring(7);
		}
		return "";
	}
複製程式碼

另外,由於每個詞可能有多個編碼,所以處理時取最高相似值的那個。

public double getSimilarity(String s1, String s2) {
		if (s1 == null && s2 == null) {
			return 1.0;
		} else if (s1 == null || s2 == null) {
			return 0.0;
		} else if (s1.equalsIgnoreCase(s2)) {
			return 1.0;
		}
		Set<String> codeSet1 = CilinDictionary.getInstance().getCilinCoding(s1);
		Set<String> codeSet2 = CilinDictionary.getInstance().getCilinCoding(s2);
		if (codeSet1 == null || codeSet2 == null) {
			return 0.0;
		}
		double similarity = 0.0;
		for (String code1 : codeSet1) {
			for (String code2 : codeSet2) {
				double s = sumWeight(code1, code2) / TOTAL_WEIGHT;
				logger.debug(code1 + "-" + code2 + "-" + sumWeight(code1, code2));
				if (similarity < s)
					similarity = s;
			}
		}
		return similarity;
	}
複製程式碼

測試

public void test() {
		String s1 = "中國人";
		String s2 = "炎黃子孫";
		CilinSimilarity cs = new CilinSimilarity();
		System.out.println(cs.getSimilarity(s1, s2));
		s1 = "汽車";
		s2 = "摩托";
		System.out.println(cs.getSimilarity(s1, s2));
		s1 = "人";
		s2 = "動物";
		System.out.println(cs.getSimilarity(s1, s2));
		s1 = "貓";
		s2 = "狗";
		System.out.println(cs.getSimilarity(s1, s2));
		s1 = "今天";
		s2 = "明天";
		System.out.println(cs.getSimilarity(s1, s2));
	}
複製程式碼
 1.0000000000000002
 0.4285714285714286
 0.0
 0.4285714285714286
 0.7857142857142858
複製程式碼

github

https://github.com/sea-boat/TextAnalyzer/blob/master/src/main/java/com/seaboat/text/analyzer/similarity/CilinSimilarity.java

-------------推薦閱讀------------

我的2017文章彙總——機器學習篇

我的2017文章彙總——Java及中介軟體

我的2017文章彙總——深度學習篇

我的2017文章彙總——JDK原始碼篇

我的2017文章彙總——自然語言處理篇

我的2017文章彙總——Java併發篇


跟我交流,向我提問:

這裡寫圖片描述

公眾號的選單已分為“讀書總結”、“分散式”、“機器學習”、“深度學習”、“NLP”、“Java深度”、“Java併發核心”、“JDK原始碼”、“Tomcat核心”等,可能有一款適合你的胃口。

為什麼寫《Tomcat核心設計剖析》

歡迎關注:

這裡寫圖片描述

相關文章