深度解析中文分詞器演算法(最大正向/逆向匹配)
阿新 • • 發佈:2019-01-23
中文分詞演算法概述:
1:非基於詞典的分詞(nlp語義領域)
相當於人工智慧領域計算。一般用於機器學習,特定領域等方法,這種在特定領域的分詞可以讓計算機在現有的規則模型中,
推理如何分詞。在某個領域(垂直領域)分詞精度較高。但是實現比較複雜。
2:基於詞典的分詞(最為常見)
這類分詞演算法比較常見,也比較簡單粗暴,比如正向/逆向匹配和ik的最細粒度。例如: mmseg分詞器 就是一種基於詞典的分詞演算法。以最大正
向匹配為主,多種 消除歧義演算法為輔。但是不管怎麼分。該類分詞方法,分詞精度不高。由於中文比較複雜,不推薦採用正向最大匹配演算法的中文
分詞器。。逆向最大匹配演算法在處理中文往
接下來分析第2種:基於詞典的分詞演算法(最長的詞優先匹配)。 先分析最大正向匹配演算法
一: 具體流程圖如下:
一:以下程式碼片段為最大正向匹配演算法:
執行正向分詞結果:package hhc.forwardAlgorithm; import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * @Description: * @Date: 2015-2-7上午02:00:51 * @Author 胡慧超 * @Version 1.0 */ @SuppressWarnings("unchecked") public class TokenizerAlgorithm { private static final List<String> DIC=new ArrayList<String>(); private static int MAX_LENGTH; /** * 把詞庫詞典轉化成dic物件,並解析詞典資訊 */ static { try { System.out.println("開始初始化字典..."); int max=1; int count=0; //讀取詞典中的每一個詞 URL url=TokenizerAlgorithm.class.getClassLoader().getResource("hhc/dic.txt"); Path path=Paths.get(url.toString().replaceAll("file:/", "")); List<String> list=Files.readAllLines(path, Charset.forName("UTF-8")); System.out.println("讀取詞典檔案結束,詞總數為:"+list.size()); for(String line:list){ DIC.add(line); count++; //獲取詞庫中 ,最大長度的詞的長度 if(line.length()>max){ max=line.length(); } } MAX_LENGTH=max; System.out.println("初始化詞典結束,最大分詞長度為:"+max+" !!"); System.out.println("------------------------------------------------------------------------"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 正向分詞演算法 * @param text * @return */ public static List forwardSeg(String text){ List result=new ArrayList(); while(text.length()>0){ int len=MAX_LENGTH; if(text.length()<MAX_LENGTH){ len=text.length(); } //取指定的最大長度 文字去字典中匹配 String tryWord=text.substring(0, len); while(!DIC.contains(tryWord)){//如果詞典中不包含該段文字 //如果長度為1 的話,且沒有在字典中匹配,返回 if(tryWord.length()==1){ break; } //如果匹配不到,則長度減1,繼續匹配 /** * --這裡就是最關鍵的地方,把最右邊的詞去掉一個,繼續迴圈 */ tryWord=tryWord.substring(0, tryWord.length()-1); } result.add(tryWord); //移除該次tryWord,繼續迴圈 text=text.substring(tryWord.length()); } return result; } public static void main(String[] args) { // TODO Auto-generated method stub List<String> lst=new ArrayList(); lst.add("研究生命起源"); lst.add("食物和服裝"); lst.add("乒乓球拍賣完了"); for(String str:lst){ List<String> list=forwardSeg(str); String word=""; for(String s:list){ s+="/"; word+=s; } System.out.println(word); } }
二:最大逆向分詞演算法
考慮到逆向,為了 區分分詞的資料的連貫性。我們採用Stack(棧物件,資料結果,後進先出,不同於Queue和ArrayList有順序的先進先出) 這個物件來儲存分詞結果。。
/** * 逆向分詞演算法 * @param text * @return */ public static List reverseSeg(String text){ Stack<String> result=new Stack(); while(text.length()>0){ int len=MAX_LENGTH; if(text.length()<MAX_LENGTH){ len=text.length(); } //取指定的最大長度 文字去字典中匹配 String tryWord=text.substring(text.length()-len); while(!DIC.contains(tryWord)){//如果詞典中不包含該段文字 //如果長度為1 的話,且沒有在字典中匹配,返回 if(tryWord.length()==1){ break; } //如果匹配不到,則長度減1,繼續匹配 /** * --這裡就是最關鍵的地方,把最左邊的詞去掉一個,繼續迴圈 */ tryWord=tryWord.substring(1); } result.add(tryWord); //移除該次tryWord,繼續迴圈 text=text.substring(0,text.length()-tryWord.length()); } int size=result.size(); List list =new ArrayList(size); for(int i=0;i<size;i++){ list.add(result.pop()); } return list; }
執行逆向分詞結果
以上程式碼實現了兩種正向和逆向的演算法,可以很明顯的比較中文分詞結果。
像之前介紹的採取正向最大匹配演算法的mmseg分詞器,內部設定了4個消除歧義的過濾演算法,這四個歧義解析規則表明是相當有效率
的。總體來講。mmseg的分詞精度還是值得推薦的。。。
還有一種不基於詞典的分詞器。簡單粗暴,ngram。