NLP 中文形近字相似度演算法開源實現

老馬嘯西風發表於2021-11-23

專案簡介

nlp-hanzi-similar 為漢字提供相似性的計算。

在這裡插入圖片描述

創作目的

有一個小夥伴說自己在做語言認知科學方向的課題研究,看了我以前寫的 NLP 中文形近字相似度計算思路

就想問下有沒有原始碼或者相關資料。

國內對於文字的相似度計算,開源的工具是比較豐富的。

但是對於兩個漢字之間的相似度計算,國內基本一片空白。國內的參考的資料少的可憐,國外相關文件也是如此。

於是將以前寫的相似度演算法整理開源,希望能幫到這位小夥伴。

本專案旨在拋磚引玉,實現一個基本的相似度計算工具,為漢字 NLP 貢獻一點綿薄之力。

特性

  • fluent 方法,一行程式碼搞定一切
  • 高度自定義,允許使用者定義自己的實現
  • 詞庫自定義,適應各種應用場景
  • 豐富的實現策略

預設實現了基於 四角編碼+拼音+漢字結構+漢字偏旁+筆畫數 的相似度比較。

變更日誌

變更日誌

快速開始

需要

jdk1.7+

maven 3.x+

maven 引入

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>nlp-hanzi-similar</artifactId>
    <version>1.0.0</version>
</dependency>

快速開始

基本用法

HanziSimilarHelper.similar 獲取兩個漢字的相似度。

double rate1 = HanziSimilarHelper.similar('末', '未');

結果為:

0.9629629629629629

自定義權重

預設是根據 四角編碼+拼音+漢字結構+漢字偏旁+筆畫數 進行相似度比較。

如果預設的系統權重無法滿足你的需求,你可以通過自定義權重調整:

double rate = HanziSimilarBs.newInstance()
                .jiegouRate(10)
                .sijiaoRate(8)
                .bushouRate(6)
                .bihuashuRate(2)
                .pinyinRate(1)
                .similar('末', '未');

自定義相似度

有些情況下,系統的計算是無法滿足的。

使用者可以在根目錄下 hanzi_similar_define.txt 進行自定義。

入人 0.9
人入 0.9

這樣在計算 的相似度時,會優先以使用者自定義的為準。

double rate = HanziSimilarHelper.similar('人', '入');

此時的結果為使用者自定義的值。

引導類

說明

為了便於使用者自定義,HanziSimilarBs 支援使用者進行自定義配。

HanziSimilarBs 中允許自定義的配置列表如下:

序號屬性說明
1bihuashuRate筆畫數權重
2bihuashuData筆畫數資料
3bihuashuSimilar筆畫數相似度策略
4jiegouRate結構權重
5jiegouData結構資料
6jiegouSimilar結構相似度策略
7bushouRate部首權重
8bushouData部首資料
9bushouSimilar部首相似度策略
10sijiaoRate四角編碼權重
12sijiaoData四角編碼資料
13sijiaoSimilar四角編碼相似度策略
14pinyinRate拼音權重
15pinyinData拼音資料
16pinyinSimilar拼音相似度策略
17hanziSimilar漢字相似度核心策略
18userDefineData使用者自定義資料

所有的配置都可以基於介面,使用者進行自定義。

快速體驗

說明

如果 java 語言不是你的主要開發語言,你可以通過下面的 exe 檔案快速體驗一下。

下載地址

https://github.com/houbb/nlp-hanzi-similar/releases/download/exe/hanzi-similar.zip

下載後直接解壓得到 hanzi-similar.exe 免安裝的可執行檔案。

執行效果

介面是使用 java swing 實現的,所以美觀什麼的,已經完全放棄治療 T_T。

使用 exe4j 打包。

字元一輸入一個漢字,字元二輸入另一個漢字,點選計算,則可以獲取對應的相似度。

在這裡插入圖片描述

字典的弊端

這個專案開源,是因為有一位小夥伴有相關的需求,但是他不懂 java。

一開始想把專案設計成為字典的形式,兩個字對應一個相似度。

但是有一個問題,2W 漢字,和 2W 漢字的相似度字典,數量已經是近億的資料量。

空間複雜度過高,同時會導致時間複雜度問題。

所以目前採用的是實時計算,有時間做一下其他語言的遷移 :)

實現原理

實現思路

不同於文字相似度,漢字相似度的單位是漢字。

所以相似度是對於漢字的拆解,比如筆畫,拼音,部首,結構等。

推薦閱讀:

NLP 中文形近字相似度計算思路

計算思路描述了實現的原理,但是小夥伴反應不會實現,於是才有了本專案。

核心程式碼

核心實現如下,就是各種相似度,進行加權計算。

/**
 * 相似度
 *
 * @param context 上下文
 * @return 結果
 * @since 1.0.0
 */
@Override
public double similar(final IHanziSimilarContext context) {
    final String charOne = context.charOne();
    final String charTwo = context.charTwo();

    //1. 是否相同
    if(charOne.equals(charTwo)) {
        return 1.0;
    }

    //2. 是否使用者自定義
    Map<String, Double> defineMap = context.userDefineData().dataMap();
    String defineKey = charOne+charTwo;
    if(defineMap.containsKey(defineKey)) {
        return defineMap.get(defineKey);
    }

    //3. 通過權重計算獲取
    //3.1 四角編碼
    IHanziSimilar sijiaoSimilar = context.sijiaoSimilar();
    double sijiaoScore = sijiaoSimilar.similar(context);

    //3.2 結構
    IHanziSimilar jiegouSimilar = context.jiegouSimilar();
    double jiegouScore = jiegouSimilar.similar(context);

    //3.3 部首
    IHanziSimilar bushouSimilar = context.bushouSimilar();
    double bushouScore = bushouSimilar.similar(context);

    //3.4 筆畫
    IHanziSimilar biahuashuSimilar = context.bihuashuSimilar();
    double bihuashuScore = biahuashuSimilar.similar(context);

    //3.5 拼音
    IHanziSimilar pinyinSimilar = context.pinyinSimilar();
    double pinyinScore = pinyinSimilar.similar(context);

    //4. 計算總分
    double totalScore = sijiaoScore + jiegouScore + bushouScore + bihuashuScore + pinyinScore;
    //4.1 避免浮點數比較問題
    if(totalScore <= 0) {
        return 0;
    }

    //4.2 正則化
    double limitScore = context.sijiaoRate() + context.jiegouRate()
            + context.bushouRate() + context.bihuashuRate() + context.pinyinRate();

    return totalScore / limitScore;
}

具體的細節,如果感興趣,可以自行閱讀原始碼。

開源地址

為了便於大家的學習和使用,本專案已開源。

開源地址:

https://github.com/houbb/nlp-hanzi-similar

歡迎大家,fork&star 鼓勵一下老馬~

演算法的優缺點

優點

為數不多的幾篇 paper 是從漢字的結構入手的。

本演算法引入了四角編碼+結構+部首+筆畫+拼音的方式,使其更加符合國內的使用直覺。

缺點

部首這部分因為當時資料問題,實際上是有缺憾的。

後續準備引入拆字字典,對漢字的所有組成部分進行對比,而不是目前一個簡單的部首。

後期 Road-MAP

  • [ ] 豐富相似度策略
  • [ ] 優化預設權重
  • [ ] 優化 exe 介面

在這裡插入圖片描述

相關文章