python中文分詞教程之前向最大正向匹配算法介紹

  前言

  中文分詞是中文文本處理的一個基礎性工作,然而長久以來,在Python編程領域,一直缺少高準確率、高效率的分詞組件。

  大家都知道,英文的分詞由於單詞間是以空格進行分隔的,所以分詞要相對的容易些,而中文就不同了,中文中一個句子的分隔就是以字爲單位的了,而所謂的正向最大匹配和逆向最大匹配便是一種分詞匹配的方法,這裏以詞典匹配說明。

  最大匹配算法是自然語言處理中的中文匹配算法中最基礎的算法,分爲正向和逆向,原理都是一樣的。

  正向最大匹配算法,故名思意,從左向右掃描尋找詞的最大匹配。

  首先我們可以規定一個詞的最大長度,每次掃描的時候尋找當前開始的這個長度的詞來和字典中的詞匹配,如果沒有找到,就縮短長度繼續尋找,直到找到或者成爲單字。

  下面話不多說了,來一起看看詳細的介紹吧。

  實例:

  S1=“計算語言學課程是三個課時” ,設定最大詞長MaxLen = 5 ,S2= " "

  字典中含有三個詞:[計算語言學]、[課程]、[課時]

  (1)S2="";S1不爲空,從S1左邊取出候選子串W="計算語言學";

  (2)查詞表,“計算語言學”在詞表中,將W加入到S2中,S2=“計算語言學/ ”, 並將W從S1中去掉,此時S1="課程是三個課時";

  (3)S1不爲空,於是從S1左邊取出候選子串W="課程是三個";

  (4)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="課程是三";

  (5)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="課程是";

  (6)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="課程"

  (7)查詞表,W在詞表中,將W加入到S2中,S2=“計算語言學/ 課程/ ”,並 將W從S1中去掉,此時S1="是三個課時";

  (8)S1不爲空,於是從S1左邊取出候選子串W="是三個課時";

  (9)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="是三個課";

  (10)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="是三個";

  (11)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="是三"

  (12)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W=“是”,這時 W是單字,將W加入到S2中,S2=“計算語言學/ 課程/ 是/ ”,並將 W從S1中去掉,此時S1="三個課時";

  (13)S1不爲空,從S1左邊取出候選子串W="三個課時";

  (14)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="三個課";

  (15)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="三個";

  (16)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W=“三”,這時 W是單字,將W加入到S2中,S2=“計算語言學/ 課程/ 是/ 三/ ”,並 將W從S1中去掉,此時S1="個課時";

  (17)S1不爲空,從S1左邊取出候選子串W="個課時";

  (18)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W="個課";

  (19)查詞表,W不在詞表中,將W最右邊一個字去掉,得到W=“個”, 這時W是單字,將W加入到S2中,S2=“計算語言學/ 課程/ 是/ 三/ 個/ ",並將W從S1中去掉,此時S1="課時";

  (20)S1不爲空,從S1左邊取出候選子串W="課時";

  (21)查詞表,W在詞表中,將W加入到S2中,S2=“計算語言學/ 課程/ 是/ 三/ 個/ 課時/ ",並將W從S1中去掉,此時S1=""。

  (22)S1爲空,輸出S2作爲分詞結果,分詞過程結束。

  而至於爲什麼選擇python這個語言呢?大概是因爲我周圍人用得少吧,我就想嘗試突破,不過我也不諱言,我的C/C++,java等等高級語言用的也不多,雖說編程語言這個東西,基本上只要熟悉一個,其他的都好學,不過我在python上嚐到了甜頭,索性就用這個語言了。

  中文分詞算法的Python實現:

  腳本接受兩個參數,一個是輸入文件的路徑,另一個是詞典的路徑。

  它的運行方法如下:

  python max-match.py

  #!/usr/bin/env python

  import cPickle as pickle

  import sys

  # 詞語最大長度爲5

  window_size=5

  def max_match_segment(line, dic):

  # write your code here

  chars = line.decode("utf8")

  words = []

  idx = 0

  # 判斷索引是否超過chars的長度

  while idx < len(chars):

  matched = False

  for i in xrange(window_size, 0, -1):

  cand=chars[idx:idx+i].encode("utf8")

  if cand in dic:

  words.append(cand)

  matched = True

  break

  # 判斷for中是否匹配到數據

  if not matched:

  i = 1鄭州婦科醫院哪家好 yiyuan.120ask.com/art/

  words.append(chars[idx].encode("utf8"))

  idx += i

  return words

  if __name__=="__main__":

  try:

  fpi=open(sys.argv[1], "r")

  except:

  print >> sys.stderr, "failed to open file"

  sys.exit(1)

  try:

  dic = pickle.load(open(sys.argv[2], "r"))

  except:

  print >> sys.stderr, "failed to load dict %s" % sys.argv[2]

  sys.exit(1)

  try:

  fpo = open("out.txt","w")

  except:

  print >> sys.stderr, "failed to load out.txt"

  sys.exit(1)

  for line in fpi:

  fpo.write("\t".join( max_match_segment(line.strip(), dic) ))

  當然,這只是最基礎的,還可以有很多高級的優化,比如說改成Trie樹版本的,控制最大詞長度的等等。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章