日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

【Python自然语言处理】中文分词技术——统计分词

發布時間:2024/7/5 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Python自然语言处理】中文分词技术——统计分词 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

中文分詞方法

本文參考自書籍《Python自然語言處理實戰:核心技術與算法》
用做個人的學習筆記和分享

1. 規則分詞

規則分詞的詳細筆記

2. 統計分詞

2.1 一般步驟

  • 建立統計語言模型。
  • 句子劃分為單詞,對劃分結果進行概率分析,獲得概率最大的分詞方式。
  • 常用統計學習算法:隱馬爾可夫、條件隨機場。
  • 2.2 語言模型

    語言模型的形式化描述:
    長度為m的字符串的概率分布:
    P(w1,w2,...,wm)=P(w1)P(w2∣w1)P(w3∣w1,w2)...P(wm∣w1,w2,...,wm?1)(1)P(w_1,w_2,...,w_m)=P(w_1)P(w_2|w_1)P(w_3|w_1,w_2)...P(w_m|w_1,w_2,...,w_{m-1}) \tag{1}P(w1?,w2?,...,wm?)=P(w1?)P(w2?w1?)P(w3?w1?,w2?)...P(wm?w1?,w2?,...,wm?1?)(1)
    其中w1w_1w1?wmw_mwm?依次表示文本中的各個詞語,采用鏈式法則計算概率值。

    n-gram模型:文本過長,計算難度大,可忽略距離大于等于n的上文詞的影響:
    P(wi∣w1,w2,...,wi?1)≈P(wi∣wi?(n?1),...,wi?1)(2)P(w_i|w_1,w_2,...,w_{i-1})≈P(w_i|w_{i-(n-1)},...,w_{i-1}) \tag{2}P(wi?w1?,w2?,...,wi?1?)P(wi?wi?(n?1)?,...,wi?1?)(2)
    一元模型:n=1,在一元語言模型中,整個句子的概率等于各個詞語概率的乘積。言下之意就是各個詞之間都是相互獨立的,這無疑是完全損失了句中的詞序信息。所以一元模型的效果并不理想:
    P(w1,w2,...,wm)=P(w1)P(w2)...P(wm)(3)P(w_1,w_2,...,w_m)=P(w_1)P(w_2)...P(w_m) \tag{3}P(w1?,w2?,...,wm?)=P(w1?)P(w2?)...P(wm?)(3)
    二元模型:n=2,式(2)變為:
    P(wi∣w1,w2,...,wi?1)≈P(wi∣wi?1)(4)P(w_i|w_1,w_2,...,w_{i-1})≈P(w_i|w_{i-1}) \tag{4}P(wi?w1?,w2?,...,wi?1?)P(wi?wi?1?)(4)
    三元模型:n=3,式(2)變為:
    P(wi∣w1,w2,...,wi?1)≈P(wi∣wi?2,wi?1)(5)P(w_i|w_1,w_2,...,w_{i-1})≈P(w_i|w_{i-2},w_{i-1}) \tag{5}P(wi?w1?,w2?,...,wi?1?)P(wi?wi?2?,wi?1?)(5)
    當n≥2 時,該模型是可以保留一定的詞序信息的,而且n 越大,保留的詞序信息越豐富,但計算成本也呈指數級增長。
    一般使用頻率計數的比例來計算n 元條件概率,如式(6)所示:
    P(wi∣wi?(n?1),...,wi?1)=count(wi?(n?1),...,wi?1,wi)count(wi?(n?1),...,wi?1)(6)P(w_i|w_{i-(n-1)},...,w_{i-1}) = \frac{count(w_{i-(n-1),...,w_{i-1},w_i})}{count(w_{i-(n-1)},...,w_{i-1})} \tag{6}P(wi?wi?(n?1)?,...,wi?1?)=count(wi?(n?1)?,...,wi?1?)count(wi?(n?1),...,wi?1?,wi??)?(6)
    當n越大時,模型包含的詞序信息越豐富,同時計算量隨之增大。與此同時,長度越長的文本序列出現的次數也會減少,如按照公式( 3.3 )估計n 元條件概率時,就會出現分子分母為零的情況。因此,一般在n 元模型中需要配合相應的平滑算法解決該問題,如拉普拉斯平滑算法等。

    2.3 隱馬爾可夫模型(HMM)

    基本思路:每個字在構造一個特定的詞語時都占據著一個確定的構詞位置( 即詞位),
    現規定每個字最多只有四個構詞位置:即B (詞首)、M (詞中)、E (詞尾)和s (單獨成詞),那么下面句子①的分詞結果就可以直接表示成如②所示的逐字標注形式:
    ①中文/文本處理/需要/進行/中文/分詞/。
    ②中/B文/E文/B本/M處/M理/E需/B要/E/進/B行/E中/B文/E/分/B詞/E。/S

    形式化描述
    句子:λ=λ1λ2...λnλ=λ_1λ_2...λ_nλ=λ1?λ2?...λn?
    標簽:σ=σ1σ2...σnσ=σ_1σ_2...σ_nσ=σ1?σ2?...σn?
    KaTeX parse error: \tag works only in display equations
    其中λiλ_iλi?是字,n為句長,σ∈{B,M,E,S}
    P(σ|λ)是關于2n個變量的條件概率,n不固定,無法對P(σ|λ)進行精確計算,故引入觀測獨立性假設:每個字的輸出僅與當前字有關。
    P(σ1σ2...σn∣λ1λ2...λn)=P(σ1∣λ1)P(σ2∣λ2)...P(σn∣λn)(8)P(σ_1σ_2...σ_n|λ_1λ_2...λ_n) = P(σ_1|λ_1)P(σ_2|λ_2)...P(σ_n|λ_n) \tag{8}P(σ1?σ2?...σn?λ1?λ2?...λn?)=P(σ1?λ1?)P(σ2?λ2?)...P(σn?λn?)(8)

    觀察獨立性假設存在的問題:完全沒有考慮上下文,且會出現不合理的情況。比如按照之前設定的B 、M 、E 和S 標記,正常來說B后面只能是M或者E ,然而基于觀測獨立性假設,我們很可能得到諸如BBB 、BEM 等的輸出,顯然是不合理的。

    HMM通過貝葉斯公式求解P(σ|λ)
    P(σ∣λ)=P(σ,λ)P(λ)=P(λ∣σ)P(σ)P(λ)(9)P(σ|λ)=\frac{P(σ,λ)}{P(λ)}=\frac{P(λ|σ)P(σ)}{P(λ)} \tag{9}P(σλ)=P(λ)P(σ,λ)?=P(λ)P(λσ)P(σ)?(9)
    λ為給定的輸入,因此P(λ)計算為常數,可以忽略,因此最大化P(σ|λ)等價于最大
    化P(λ|σ)P(σ)。
    對P(λ|σ)P(σ)做馬爾可夫假設
    P(λ∣σ)=P(λ1∣σ1)P(λ2∣σ2)...P(λn∣σn)(10)P(λ|σ)=P(λ_1|σ_1)P(λ_2|σ_2)...P(λ_n|σ_n) \tag{10}P(λσ)=P(λ1?σ1?)P(λ2?σ2?)...P(λn?σn?)(10)
    P(σ)=P(σ1)P(σ2∣σ1)P(σ3∣σ1,σ2)???P(σn∣σ1,σ2,…,σn?1(11)P(σ) = P(σ_1)P(σ_2|σ_1)P(σ_3|σ_1,σ_2)···P(σ_n|σ_1,σ_2,…,σ_{n-1}\tag{11}P(σ)=P(σ1?)P(σ2?σ1?)P(σ3?σ1?,σ2?)???P(σn?σ1?,σ2?,,σn?1?(11)
    HMM做齊次馬爾可夫假設
    P(σ)=P(σ1)P(σ2∣σ1)P(σ3∣σ2)...P(σn∣σn?1)(12)P(σ)=P(σ_1)P(σ_2|σ_1)P(σ_3|σ_2)...P(σ_n|σ_{n-1}) \tag{12}P(σ)=P(σ1?)P(σ2?σ1?)P(σ3?σ2?)...P(σn?σn?1?)(12)

    綜上所述:
    P(λ∣σ)P(σ)~P(λ1∣σ1)P(σ2∣σ1)P(λ2∣σ2)P(σ3∣σ2)...P(σn∣σn?1)P(λn∣σn)P(λ|σ)P(σ)~P(λ_1|σ_1)P(σ_2|σ_1)P(λ_2|σ_2)P(σ_3|σ_2)...P(σ_n|σ_{n-1})P(λ_n|σ_n)P(λσ)P(σ)P(λ1?σ1?)P(σ2?σ1?)P(λ2?σ2?)P(σ3?σ2?)...P(σn?σn?1?)P(λn?σn?)
    其中P(λk∣σk)P(λ_k|σ_k)P(λk?σk?)式發射概率,P(σk∣σk?1)P(σ_k|σ_{k-1})P(σk?σk?1?)是轉移概率,設置P(σk∣σk?1)=0P(σ_k|σ_{k-1})=0P(σk?σk?1?)=0可以排除BBB、EM等不合理的組合。

    求解maxP(λ|σ)P(σ):常用Veterbi算法,算法效率O(n?l2)O(n*l^2)O(n?l2),l為候選數目最多的節點σiσ_iσi?的候選數目,與n成正比。
    Veterbi算法:是一種動態規劃方法,核心思想是:如果最終的最優路徑經過某個σiσ_iσi?,那么從初始節點到σi?1σ_{i-1}σi?1?點的路徑必然也是一個最優路徑一一因為每一個節點σiσ_iσi?只會影響前后兩個P(σi?1∣σi)P(σ_{i-1}|σ_{i})P(σi?1?σi?)P(σi∣σi+1)P(σ_i|σ_{i+1})P(σi?σi+1?)。

    HMM狀態轉移示意圖如下圖所示:

    2.4 HMM的Python實現

  • 定義HMM類,包含_init_方法、try_load_model方法、train方法
  • init:初始化一些全局信息,用于初始化一些成員變量。如狀態集合(標記
    S 、B 、E 、M ),以及存取概率計算的中間文件。
  • def __init__(self):import os# 主要是用于存取算法中間結果,不用每次都訓練模型self.model_file = './data/hmm_model.pkl'# 狀態值集合self.state_list = ['B', 'M', 'E', 'S']# 參數加載,用于判斷是否需要重新加載model_fileself.load_para = False
  • try_load_model:接收一個參數,用于判別是否加載中間文件結果。當直接加載中間結果時,可以不通過語料庫訓練,直接進行分詞調用。否則,該函數用于初始化初始概率、轉移概率以及發射概率等。
  • # 用于加載已計算的中間結果,當需要重新訓練時,需初始化清空結果 def try_load_model(self, trained):if trained:import picklewith open(self.model_file, 'rb') as f:self.A_dic = pickle.load(f)self.B_dic = pickle.load(f)self.Pi_dic = pickle.load(f)self.load_para = Trueelse:# 狀態轉移概率(狀態->狀態的條件概率)self.A_dic = {}# 發射概率(狀態->詞語的條件概率)self.B_dic = {}# 狀態的初始概率self.Pi_dic = {}self.load_para = False
  • train:主要用于通過給定的分詞語料進行訓練。語料的格式為每行一句話(這里以逗號隔開也算一句),每個詞以空格分隔,這里采用了人民日報的分詞語料。該函數主要通過對語料的統計, 得到HMM 所需的初始概率、轉移概率以及發射概率。
  • # 計算轉移概率、發射概率以及初始概率 def train(self, path):# 重置幾個概率矩陣self.try_load_model(False)# 統計狀態出現次數,求p(o)Count_dic = {}# 初始化參數def init_parameters():for state in self.state_list:self.A_dic[state] = {s: 0.0 for s in self.state_list}self.Pi_dic[state] = 0.0self.B_dic[state] = {}Count_dic[state] = 0def makeLabel(text):out_text = []if len(text) == 1:out_text.append('S')else:out_text += ['B'] + ['M'] * (len(text) - 2) + ['E']return out_textinit_parameters()line_num = -1# 觀察者集合,主要是字以及標點等words = set()with open(path, encoding='utf8') as f:for line in f:line_num += 1line = line.strip()if not line:continueword_list = [i for i in line if i != ' ']words |= set(word_list) # 更新字的集合linelist = line.split()line_state = []for w in linelist:line_state.extend(makeLabel(w))assert len(word_list) == len(line_state)for k, v in enumerate(line_state):Count_dic[v] += 1if k == 0:self.Pi_dic[v] += 1 # 每個句子的第一個字的狀態,用于計算初始狀態概率else:self.A_dic[line_state[k - 1]][v] += 1 # 計算轉移概率self.B_dic[line_state[k]][word_list[k]] =\self.B_dic[line_state[k]].get(word_list[k], 0) + 1.0 # 計算發射概率self.Pi_dic = {k: v * 1.0 / line_num for k, v in self.Pi_dic.items()}self.A_dic = {k: {k1: v1 / Count_dic[k] for k1, v1 in v.items()}for k, v in self.A_dic.items()}# 加1平滑self.B_dic = {k: {k1: (v1 + 1) / Count_dic[k] for k1, v1 in v.items()}for k, v in self.B_dic.items()}# 序列化import picklewith open(self.model_file, 'wb') as f:pickle.dump(self.A_dic, f)pickle.dump(self.B_dic, f)pickle.dump(self.Pi_dic, f)return self
  • veterbi方法:為Veterbi 算法的實現,是基于動態規劃的一種實現,主要是求最大概率的路徑。其輸入參數為初始概率、轉移概率以及發射概率,加上需要切分的句子。
  • def veterbi(self, text, states, start_p, trans_p, emit_p):V = [{}]path = {}for y in states:V[0][y] = start_p[y] * emit_p[y].get(text[0], 0)path[y] = [y]for t in range(1, len(text)):V.append({})newpath = {}# 檢驗訓練的發射概率矩陣中是否有該字neverSeen = text[t] not in emit_p['S'].keys() and \text[t] not in emit_p['M'].keys() and \text[t] not in emit_p['E'].keys() and \text[t] not in emit_p['B'].keys()for y in states:emitP = emit_p[y].get(text[t], 0) if not neverSeen else 1.0 # 設置未知字單獨成詞(prob, state) = max([(V[t - 1][y0] * trans_p[y0].get(y, 0) *emitP, y0)for y0 in states if V[t - 1][y0] > 0])V[t][y] = probnewpath[y] = path[state] + [y]path = newpathif emit_p['M'].get(text[-1], 0) > emit_p['S'].get(text[-1], 0):(prob, state) = max([(V[len(text) - 1][y], y) for y in ('E', 'M')])else:(prob, state) = max([(V[len(text) - 1][y], y) for y in states])return (prob, path[state])
  • cut方法:用于分詞,其通過加載中間文件,調用veterbi 函數來完成。
  • def cut(self, text):import osif not self.load_para:self.try_load_model(os.path.exists(self.model_file))prob, pos_list = self.viterbi(text, self.state_list, self.Pi_dic, self.A_dic, self.B_dic)begin, next = 0, 0for i, char in enumerate(text):pos = pos_list[i]if pos == 'B':begin = ielif pos == 'E':yield text[begin: i + 1]next = i + 1elif pos == 'S':yield charnext = i + 1if next < len(text):yield text[next:]
  • 主函數
  • if __name__ == '__main__':hmm = HMM()hmm.train('./data/trainCorpus.txt_utf8')text = '這是一個非常棒的方案!'res = hmm.cut(text)print(text)print(str(list(res)))# 分詞結果:[’這是’, ’ 一個’, ’ 非?!?#xff0c; ’ 棒·, ’ 的’ , ’ 方案’ , ' !' l

    2.5 其他統計分詞算法

    條件隨機場CRF:基于馬爾可夫思想的統計模型。在隱含馬爾可夫中,有個很經典的假設,那就是每個狀態只與它前面的狀態有關。這樣的假設顯然是有偏差的,于是學者們提出了條件隨機場算法,使得每個狀態不止與他前面的狀態有關,還與他后面的狀態有關

    神經網絡分詞算法:深度學習方法在NLP 上的應用。通常采用CNN 、LSTM 等深度學習網絡自動發現一些模式和特征,然后結合C RF , softmax 等分類算法進行分詞預測。

    2.6 總結

    對比機械分詞法,這些統計分詞方法不需耗費人力維護詞典,能較好地處理歧義和未登錄詞,是目前分詞中非常主流的方法。但其分同的效果很依賴訓練語料的質量,且計算量相較于機械分詞要大得多。

    總結

    以上是生活随笔為你收集整理的【Python自然语言处理】中文分词技术——统计分词的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。