專案簡介
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 中允許自定義的配置列表如下:
序號 | 屬性 | 說明 |
---|---|---|
1 | bihuashuRate | 筆畫數權重 |
2 | bihuashuData | 筆畫數資料 |
3 | bihuashuSimilar | 筆畫數相似度策略 |
4 | jiegouRate | 結構權重 |
5 | jiegouData | 結構資料 |
6 | jiegouSimilar | 結構相似度策略 |
7 | bushouRate | 部首權重 |
8 | bushouData | 部首資料 |
9 | bushouSimilar | 部首相似度策略 |
10 | sijiaoRate | 四角編碼權重 |
12 | sijiaoData | 四角編碼資料 |
13 | sijiaoSimilar | 四角編碼相似度策略 |
14 | pinyinRate | 拼音權重 |
15 | pinyinData | 拼音資料 |
16 | pinyinSimilar | 拼音相似度策略 |
17 | hanziSimilar | 漢字相似度核心策略 |
18 | userDefineData | 使用者自定義資料 |
所有的配置都可以基於介面,使用者進行自定義。
快速體驗
說明
如果 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 介面