1. 程式人生 > >中文分詞實現——雙向最大匹配

中文分詞實現——雙向最大匹配

關於中文分詞的一些基本介紹,可以看這篇部落格《中文分詞方法總結》。這裡就不再進行詳細介紹了。

雙向最大匹配方法

雙向最大匹配方法是一種基於詞典的分詞方法。基於詞典的分詞方法是按照一定策略將待分析的漢字串與一個“大機器詞典”中的詞條進行匹配,若在詞典中找到某個字串,則匹配成功。

按照掃描方向的不同:正向匹配和逆向匹配

按照長度的不同:最大匹配和最小匹配

正向最大匹配思想FMM

1.從左向右取待切分漢語句的m個字元作為匹配欄位,m為大機器詞典中最長詞條個數。

2.查詢大機器詞典並進行匹配。若匹配成功,則將這個匹配欄位作為一個詞切分出來。

若匹配不成功,則將這個匹配欄位的最後一個字去掉,剩下的字串作為新的匹配欄位,進行再次匹配,重複以上過程,直到切分出所有詞為止。

逆向最大匹配演算法BMM

該演算法是正向最大匹配的逆向思維,匹配不成功,將匹配欄位的最前一個字去掉,實驗表明,逆向最大匹配演算法要優於正向最大匹配演算法。

雙向最大匹配法(Bi-directction Matching method,BM)

    雙向最大匹配法是將正向最大匹配法得到的分詞結果和逆向最大匹配法的到的結果進行比較,從而決定正確的分詞方法。據SunM.S. 和 Benjamin K.T.(1995)的研究表明,中文中90.0%左右的句子,正向最大匹配法和逆向最大匹配法完全重合且正確,只有大概9.0%的句子兩種切分方法得到的結果不一樣,但其中必有一個是正確的(歧義檢測成功),只有不到1.0%的句子,或者正向最大匹配法和逆向最大匹配法的切分雖重合卻是錯的,或者正向最大匹配法和逆向最大匹配法切分不同但兩個都不對(歧義檢測失敗)。這正是雙向最大匹配法在實用中文資訊處理系統中得以廣泛使用的原因所在。

在本文實現的方法中,是綜合考慮了正向和逆向最大匹配的結果,加入了一些啟發式的規則來對分詞結果進行進一步消歧的。

啟發式規則:

    1.如果正反向分詞結果詞數不同,則取分詞數量較少的那個。

    2.如果分詞結果詞數相同

                 a.分詞結果相同,就說明沒有歧義,可返回任意一個。

                 b.分詞結果不同,返回其中單字較少的那個。

下面是具體實現

package Segment;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;


public class FBSegment {
	private static Set<String> seg_dict;
	
	//載入詞典
	public static void Init(){
		seg_dict = new HashSet<String>();
		String dicpath = "data/worddic.txt";
		String line = null;
		
		BufferedReader br;
		try{
			br = new BufferedReader( new InputStreamReader( new FileInputStream(dicpath)));	
			while((line = br.readLine()) != null){
				line = line.trim();
				if(line.isEmpty())
					continue;	
				seg_dict.add(line);
			}
			br.close();
		}catch(IOException e){
			e.printStackTrace();
		}
		
	}
	/**
	 * 前向演算法分詞
	 * @param seg_dict 分詞詞典
	 * @param phrase 待分詞句子
	 * @return 前向分詞結果
	 */
	private static Vector<String> FMM2( String  phrase){
		int maxlen = 16;
		Vector<String> fmm_list = new Vector<String>();
		int len_phrase = phrase.length();
		int i=0,j=0;
		
		while(i < len_phrase){
			int end = i+maxlen;
			if(end >= len_phrase)
				end = len_phrase;
			String phrase_sub = phrase.substring(i, end);
			for(j = phrase_sub.length(); j >=0; j--){
				if(j == 1)
					break;
				String key =  phrase_sub.substring(0, j);
				if(seg_dict.contains(key)){
					fmm_list.add(key);
					i +=key.length() -1;
					break;
				}
			}
			if(j == 1)
				fmm_list.add(""+phrase_sub.charAt(0));
			i+=1;
		}
		return fmm_list;
	}
	
	/**
	 * 後向演算法分詞
	 * @param seg_dict 分詞詞典
	 * @param phrase 待分詞句子
	 * @return 後向分詞結果
	 */
	private static Vector<String> BMM2( String  phrase){
		int maxlen = 16;
		Vector<String> bmm_list = new Vector<String>();
		int len_phrase = phrase.length();
		int i=len_phrase,j=0;
		
		while(i > 0){
			int start = i - maxlen;
			if(start < 0)
				start = 0;
			String phrase_sub = phrase.substring(start, i);
			for(j = 0; j < phrase_sub.length(); j++){
				if(j == phrase_sub.length()-1)
					break;
				String key =  phrase_sub.substring(j);
				if(seg_dict.contains(key)){
					bmm_list.insertElementAt(key, 0);
					i -=key.length() -1;
					break;
				}
			}
			if(j == phrase_sub.length() -1)
				bmm_list.insertElementAt(""+phrase_sub.charAt(j), 0);
			i -= 1;
		}
		return bmm_list;
	}
		
	/**
	 * 該方法結合正向匹配和逆向匹配的結果,得到分詞的最終結果
	 * @param FMM2 正向匹配的分詞結果
	 * @param BMM2 逆向匹配的分詞結果
	 * @param return 分詞的最終結果
	 */
	public static Vector<String> segment( String phrase){
		Vector<String> fmm_list = FMM2(phrase);
		Vector<String> bmm_list = BMM2(phrase);
		//如果正反向分詞結果詞數不同,則取分詞數量較少的那個
		if(fmm_list.size() != bmm_list.size()){
			if(fmm_list.size() > bmm_list.size())
				return bmm_list;
			else return fmm_list;
		}
		//如果分詞結果詞數相同
		else{
			//如果正反向的分詞結果相同,就說明沒有歧義,可返回任意一個
			int i ,FSingle = 0, BSingle = 0;
			boolean isSame = true;
			for(i = 0; i < fmm_list.size();  i++){
				if(!fmm_list.get(i).equals(bmm_list.get(i)))
					isSame = false;
				if(fmm_list.get(i).length() ==1)
					FSingle +=1;
				if(bmm_list.get(i).length() ==1)
					BSingle +=1;
			}
			if(isSame)
				return fmm_list;
			else{
				//分詞結果不同,返回其中單字較少的那個
				if(BSingle > FSingle)
					return fmm_list;
				else return bmm_list;
			}
		}
	}
	public static void main(String [] args){
		String test = "我是一個學生";
		FBSegment.Init();
		System.out.println(FBSegment.segment(test));
	}
}

輸出:[我, 是, 一個, 學生]

參考:

中文分詞演算法筆記 http://www.cnblogs.com/lvpei/archive/2010/08/04/1792409.html;

中文分詞演算法總結  http://blog.csdn.net/chenlei0630/article/details/40710325;


相關推薦

中文實現——雙向匹配

關於中文分詞的一些基本介紹,可以看這篇部落格《中文分詞方法總結》。這裡就不再進行詳細介紹了。 雙向最大匹配方法 雙向最大匹配方法是一種基於詞典的分詞方法。基於詞典的分詞方法是按照一定策略將待分析的漢字串與一個“大機器詞典”中的詞條進行匹配,若在詞典中找到某個字串,則匹配成功

詞法分析-中文技術-正向匹配法與逆向匹配

Long Time No See... 最近深受痛苦的折磨,這一年來所有的事跌宕起伏,如同一瞬,一個個打擊接踵而至,從年初的各種擦邊掛,到各種失敗,各種放棄,似乎沒有發生一個順心的事,不知道從什麼時候起戾氣變得越來越重,更無與人說。不管如何,“盡吾志也而不能至者,可以無悔矣,其孰能譏之乎?”……

中文的逆向匹配演算法(2016年)

逆向最大匹配演算法,中文分詞機械化分詞中最基本的演算法,也是入門級別的演算法。但是,在機械化分詞方面的效果,表現卻很好。尤其是在大文字的時候,一次取較多詞語進行匹配,因為大文字匹配成詞的概率遠遠高於小文字,所以會有很好的表現。下面的程式碼,來自IK分詞的一部分原始碼包,201

中文之正向匹配演算法

中文分詞目前可以分為“規則分詞”,“統計分詞”,“混合分詞(規則+統計)”這三個主要流派。這次介紹下基於規則的分詞,其是一種機械的分詞方法,主要通過維護詞典,在切分語句時,將語句的每個字串與詞表中的詞逐一進行匹配,找到則切分,否則不予切分。 正向最大匹配演算法

中文演算法之正向匹配演算法(Python版)

最大匹配演算法是自然語言處理中的中文匹配演算法中最基礎的演算法,分為正向和逆向,原理都是一樣的。 正向最大匹配演算法,故名思意,從左向右掃描尋找詞的最大匹配。 首先我們可以規定一個詞的最大長度,每次掃描的時候尋找當前開始的這個長度的詞來和字典中的詞匹配,如果沒有找到,就縮短

演算法:正向匹配演算法

正向最大匹配演算法 正向最大匹配演算法(FMM)是一種基於詞典的分詞方法,同樣的基於詞典的方法還有逆向最大匹配法(RMM),ngram法.FMM故名思意,左向右掃描尋找詞的最大匹配,是一種貪心的思想。

雙向匹配演算法——基於詞典規則的中文(Java實現)

目錄 一、中文分詞理論描述 二、演算法描述       1、正向最大匹配演算法       2、反向最大匹配演算法       3、雙劍合璧 三、案例描述 四、JAVA實現完整程式碼 五、組

自己動手寫引擎——逆向、正向雙向演算法的實現

分詞引擎已經是NLP最成熟的部分了,經歷了:字典分詞,統計分詞等發展之後,除了應付學術中才有的各種變態歧義句之外,目前工業界的分詞引擎對於絕大多數的常見問題已經足以應對,頂多是需要不斷優化新詞字典就可以了。 但不管怎麼樣,對於一個NLPer還是要能夠手寫最簡單的分詞演算法的

Python下的中文實現

一 安裝和測試Python下的中文分詞工具 的帖子“四款python中文分詞系統簡單測試”。 從評測的結果來看 在Python下可以採用的較好的中文分詞工具是結巴中文分詞和中科院的分詞系統。 對於這兩個工具進行測試。 1 安裝結巴中文分詞工具 在32位,Windows7

中文--正向匹配算法python實現

命中 col odin app () 切分 -- \n 多個 最大匹配法:最大匹配是指以詞典為依據,取詞典中最長單詞為第一個次取字數量的掃描串,在詞典中進行掃描(為提升掃描效率,還可以跟據字數多少設計多個字典,然後根據字數分別從不同字典中進行掃描)。例如:詞典中最長詞為“中

一個簡單正向匹配(Maximum Matching)MM中文演算法的實現

1.構建詞典記憶體樹的TrieNode節點類:       package cn.wzb.segmenter.mm.bean; import java.util.HashMap; /** * 構建記憶體詞典的Trie樹結點 * */ public cla

中文--逆向匹配

res 最長 java 搜索字符串 name ++ san imp 匹配 上一篇文章中介紹了正向最大匹配。能夠看到有時候效果不是非常好。這裏在介紹一種逆向最大匹配的算法。詞典和匹配的字符串都和上一篇文章同樣 僅僅是本算法是從後到前搜索字符串。然後找到最長的

熵模型進行字標註中文(Python實現

        同前面的那篇文章一樣(參見:最大熵模型進行中文分詞),本文運用字標註法進行中文分詞,分別使用4-tag和6-tag對語料進行字標註,觀察分詞效果。前面的文章中使用了模型工具包中自帶的一個樣例進行4-tag中文分詞,但由於其選取的特徵是針對英文詞性標註開發

用正向和逆向匹配演算法進行中文(續)

一、結果分析:         1.程式執行結果,如下圖所示:         2.總體分析。         (1)正向和逆向匹配都正確的句子數目為 1731,佔句子總數的39.0%         (2)正向最大匹配完全正確的句子數目為 1917,佔句子總數的43

中文——正向匹配

中文分詞應用很廣泛,網上也有很多開源專案。我在這裡主要講一下中文分詞裡面演算法的簡單實現,廢話不多說了,現在先上程式碼 package com; import java.util.ArrayList; import java.util.List; public cl

深度解析中文器演算法(正向/逆向匹配

中文分詞演算法概述:  1:非基於詞典的分詞(nlp語義領域)     相當於人工智慧領域計算。一般用於機器學習,特定領域等方法,這種在特定領域的分詞可以讓計算機在現有的規則模型中, 推理如何分詞。在某個領域(垂直領域)分詞精度較高。但是實現比較複雜。 2:基於詞典的分

基於Tire樹和概率法的中文功能的Java實現

對於分詞系統的實現來說,主要應集中在兩方面的考慮上:一是對語料庫的組織,二是分詞策略的制訂。 1.   Tire樹 Tire樹,即字典樹,是通過字串的公共字首來對字串進行統計、排序及儲存的一種樹形結構。其具有如下三個性質: 1)      根節點不包含字元(或漢字),除根節

HMM匹配演算法(Python)

正向最大匹配演算法是我國最早提出的解決中文分詞問題的演算法,因其簡單易操作,至今仍作為機器分詞的粗分演算法,在今天看來,這種演算法的準確率遠不夠高,無法達到令人滿意的要求。這只是一次練習。 待切分

中文熵馬爾可夫模型MEMM

Xue & Shen '2003 [2]用兩種序列標註模型——MEMM (Maximum Entropy Markov Model)與CRF (Conditional Random Field)——用於中文分詞;看原論文感覺作者更像用的是MaxEnt (Maximum Entropy) 模型而非MEM

熵模型進行中文

        本文運用字標註法進行中文分詞,最大熵模型方面使用開源的張樂博士的最大熵模型工具包(Maximum Entropy Modeling Toolkit for Python and C++)。使用的中文語料資源是SIGHAN提供的backoff 2005語料,