前言
词语的相似性的计算方法有很多, 比如字面相似度计算方法, 基于语义词典的计算方法, 基于统计的相似度 (向量空间模型) 计算方法和基于神经网络的相似度计算方法.
本篇文章讲讲基于词林的语义相似性.
词林
同义词词林是上世纪 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
来源: https://juejin.im/post/5b343193e51d4558c0444590