同义词相似度可以怎样计算
- - IT瘾-dev词语的相似性的计算方法有很多,比如字面相似度计算方法、基于语义词典的计算方法、基于统计的相似度(向量空间模型)计算方法和基于神经网络的相似度计算方法. 本篇文章讲讲基于词林的语义相似性. 《同义词词林》是上世纪80年代出版的对汉语词汇进行语义分类的义类词典,共收录64223条词目. 随后发展,哈尔滨工业大学信息检索实验室对其进行修正完善,《哈工大社会计算与信息检索研究中心同义词词林扩展版》. 
词语的相似性的计算方法有很多,比如字面相似度计算方法、基于语义词典的计算方法、基于统计的相似度(向量空间模型)计算方法和基于神经网络的相似度计算方法。
本篇文章讲讲基于词林的语义相似性。
《同义词词林》是上世纪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   
 https://github.com/sea-boat/TextAnalyzer/blob/master/src/main/java/com/seaboat/text/analyzer/similarity/CilinSimilarity.java