python 實現中文分詞統計

will233發表於2019-02-16

總是看到別人用Python搞各種統計,前端菜鳥的我也來嘗試了一把。有各種語義分析庫在,一切好像並不是很複雜。不過Python剛開始看,估計程式碼有點醜。

一、兩種中文分詞開發包

thulac (http://thulac.thunlp.org/)

THULAC(THU Lexical Analyzer for Chinese)由清華大學自然語言處理與社會人文計算實驗室研製推出的一套中文詞法分析工具包,具有中文分詞和詞性標註功能。THULAC具有如下幾個特點:

  • 能力強。利用我們整合的目前世界上規模最大的人工分詞和詞性標註中文語料庫(約含5800萬字)訓練而成,模型標註能力強大。
  • 準確率高。該工具包在標準資料集Chinese Treebank(CTB5)上分詞的F1值可達97.3%,詞性標註的F1值可達到92.9%,與該資料集上最好方法效果相當。
  • 速度較快。同時進行分詞和詞性標註速度為300KB/s,每秒可處理約15萬字。只進行分詞速度可達到1.3MB/s。

jieba (https://github.com/fxsjy/jieba

據說是最好的中文分片語件,支援Python、C++、Java、node.js、PHP等多種語言。

  • 支援三種分詞模式()

    • 精確模式,試圖將句子最精確地切開,適合文字分析;
    • 全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;
    • 搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜尋引擎分詞。
  • 支援繁體分詞
  • 支援自定義詞典
  • MIT 授權協議

二、語義分詞

2.1 簡單文字分詞

兩種分片語件的使用都比較簡單,以 jieba 為例:

# -*- coding: utf-8 -*-
import jieba
# 精確模式
seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print "Default Mode: " + "/ ".join(seg_list)
#輸出結果:
#Default Mode: 我/ 來到/ 北京/ 清華大學

2.2 對檔案內容進行分詞

對檔案內容進行分詞其實本質上和對字串的分詞一樣,只不過多了個檔案讀寫的過程。
這裡寫了兩個讀寫檔案的函式,之所以使用codecs來讀取,主要是為了解決Python2.7 檔案讀寫過程中Unicode編碼問題

# -*- coding: utf-8 -*-
import codecs
# @see 讀取檔案內容
def readFile(filename):
  content = ""
  try:
    fo = codecs.open(filename,`r`, "utf-8")
    print "讀取檔名:", filename
    for line in fo.readlines():
      content += line.strip()
    print "字數:", len(content)
  except IOError as e:
    print "檔案不存在或者檔案讀取失敗"
    return ""
  else:
    fo.close()
    return content
    
# @see 寫入檔案內容(陣列會使用writelines進行寫入)codec.open實現
# @param toFile 檔名
#        content 內容
def writeFile(toFile, content):
  try:
    fo = codecs.open(toFile, `wb`, "utf-8")
    print "檔名:", toFile
    if type(content) == type([]):
      fo.writelines(content)
    else:
      fo.write(content)
  except IOError:
    print "沒有找到檔案或檔案讀取失敗"
  else:
    print "檔案寫入成功"
    fo.close()
    

將檔案讀寫和分詞結合起來

# 讀取原始檔(sourceFile)內容
rawContent = readFile(sourceFile)
# 結巴分詞
seg_list = jieba.cut(rawContent, cut_all=False)
# 把分詞結果寫到目標檔案(targetFile)中,這裡是用空格分割,也可以改成其他符號
writeFile(targetFile, " ".join(seg_list))

三、對分詞結果進行統計和排序

簡單說一下思路,讀取分詞結果的txt檔案,然後用空格分割成詞語陣列,遍歷陣列,分別統計詞語的出現次數。最後對所有的單詞根據頻次進行排序。

3.1 統計分詞

# 詞語陣列
wordList= []
# 用於統計詞頻
wordCount= {}

# 從分詞後的原始檔中讀取資料
sourceData = readFile(sourceFile)
# 利用空格分割成陣列
wordList = sourceData.split(` `)
# 遍歷陣列進行詞頻統計,這裡使用wordCount 物件,出發點是物件下標方便查詢
for item in wordList:
  if item not in wordCount:
    wordCount[item] = 1
  else:
    wordCount[item] += 1
# 迴圈結束,wordCount 物件將儲存所有的詞語和詞頻

3.2 根據詞頻排序

Python 陣列中自帶sort() 函式,為了方便比較,我們定義了一個物件,並標明瞭比較方法

# 定義wordItem 類
class wordItem:
  label = ``
  times = 0
  # 建構函式
  def __init__(self, l, t):
    self.label = l
    self.times = t
  # 用於比較
  def __lt__(self, other):
    return self.times < other.times

# 定義wordItem 陣列用於排序
wordItemArray= []
# 構造物件陣列
for key in wordCount:
  wordItemArray.append(wordItem(key, wordCount[key]))
# 按詞頻由高到低倒序排列
wordItemArray.sort(reverse = True)

# 寫入目標檔案 target
wf = codecs.open(targetFile,`w`, "utf-8")
for item in wordItemArray:
  wf.write(item.label+` `+str(item.times) + `
`)

四、使用命令列

使用命令列需要引入import sys,通過sys.argv[n]可以獲得輸入的命令列引數,注意第一個是指令碼名。

import sys
# 我們呼叫時會 python index.py `source.txt` `target.txt`
# 注意這裡argv 是指令碼名
# print "name: ", sys.argv[0] # 指令碼名 如:index.py
sourceFile = sys.argv[1]
targetFile = sys.argv[2]

五、完整程式碼

參見 github node-popcorn,專案中加入了一些puppeteer無頭瀏覽器爬蟲抓取網頁內容的程式碼。

相關文章