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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自然语言处理系列之:中文分词技术

發(fā)布時間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自然语言处理系列之:中文分词技术 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

大綱

  • 中文分詞的概念與分類

  • 常用分詞(規(guī)則分詞、統(tǒng)計分詞、混合分詞)技術(shù)介紹

  • 開源中文分詞工具-Jieba

  • 實戰(zhàn)分詞之高頻詞提取


3.1 中文分詞簡介

  • 規(guī)則分詞

    最早興起,主要通過人工設(shè)立詞庫,按照一定方式進行匹配切分,實現(xiàn)簡單高效,但對新詞難以處理;

  • 統(tǒng)計分詞

    能較好應(yīng)對新詞發(fā)現(xiàn)場景,但是太過于依賴于語料質(zhì)量;

  • 混合分詞

    規(guī)則分詞與統(tǒng)計分詞的結(jié)合體;


  • 3.2 規(guī)則分詞

    • 定義

      一種機械分詞方法,主要通過維護詞典,切分語句時,將語句中的每個字符串與詞表中的詞逐一匹配,找到則切分,否則不切分;

    • 分類

      • 正向最大匹配法(Maximum Match Method,MM法)
    • 基本思想

      假定分詞詞典中最長詞有iii個漢字字符,則用被處理文檔的當前字符串中的前iii個字作為匹配字段,查找字典;

    • 算法描述

      • 從左向右取待切分漢語句的mmm個字符作為匹配字段,mmm是機器詞典中最長詞條的字符數(shù);
      • 查找機器詞典并進行匹配。匹配成功則將匹配字段作為一個詞切分出來,匹配失敗則將匹配字段的最后一個字去掉,剩下的字符串作為新的匹配字段,進行再匹配,一直重復(fù)上述過程指導(dǎo)切分出所有詞;
      • 逆向最大匹配法(Reverse Maximum Match Method,RMM法)
    • 基本原理

      從被處理文檔末端開始匹配掃描,每次取末端的iii個字符作為匹配字段,匹配事變則去掉匹配字段最前一個字,繼續(xù)匹配;

      • 雙向最大匹配(Bi-direction Matching Method)
    • 基本原理

      將正向最大匹配法和逆向最大匹配法得到的分詞結(jié)果進行比較,庵后按照最大匹配原則,選取詞數(shù)切分最少的作為結(jié)果;

    • 相關(guān)代碼

  • 正向最大匹配
  • #!/usr/bin/env python # -*- coding: utf-8 -*- # @version : 1.0 # @Time : 2019-8-25 15:27 # @Author : cunyu # @Email : cunyu1024@foxmail.com # @Site : https://cunyu1943.github.io # @File : mm.py # @Software: PyCharm # @Desc : 正向最大匹配分詞train_data = './data/train.txt' # 訓(xùn)練語料 test_data = './data/test.txt' # 測試語料 result_data = './data/test_sc_zhengxiang.txt' # 生成結(jié)果def get_dic(train_data): # 讀取文本返回列表with open(train_data, 'r', encoding='utf-8', ) as f:try:file_content = f.read().split()finally:f.close()chars = list(set(file_content))return charsdef MM(test_data, result_data, dic):# 詞的最大長度max_length = 5h = open(result_data, 'w', encoding='utf-8', )with open(test_data, 'r', encoding='utf-8', ) as f:lines = f.readlines()for line in lines: # 分別對每行進行正向最大匹配處理max_length = 5my_list = []len_hang = len(line)while len_hang > 0:tryWord = line[0:max_length]while tryWord not in dic:if len(tryWord) == 1:breaktryWord = tryWord[0:len(tryWord) - 1]my_list.append(tryWord)line = line[len(tryWord):]len_hang = len(line)for t in my_list: # 將分詞結(jié)果寫入生成文件if t == '\n':h.write('\n')else:print(t)h.write(t + " ")h.close()if __name__ == '__main__':print('讀入詞典')dic = get_dic(train_data)print('開始匹配')MM(test_data, result_data, dic)
  • 逆向最大匹配
  • #!/usr/bin/env python # -*- coding: utf-8 -*- # @version : 1.0 # @Time : 2019-8-25 15:36 # @Author : cunyu # @Email : cunyu1024@foxmail.com # @Site : https://cunyu1943.github.io # @File : rmm.py # @Software: PyCharm # @Desc : 逆向最大匹配法train_data = './data/train.txt' test_data = './data/test.txt' result_data = './data/test_sc.txt'def get_dic(train_data):with open(train_data, 'r', encoding='utf-8', ) as f:try:file_content = f.read().split()finally:f.close()chars = list(set(file_content))return charsdef RMM(test_data,result_data,dic):max_length = 5h = open(result_data, 'w', encoding='utf-8', )with open(test_data, 'r', encoding='utf-8', ) as f:lines = f.readlines()for line in lines:my_stack = []len_hang = len(line)while len_hang > 0:tryWord = line[-max_length:]while tryWord not in dic:if len(tryWord) == 1:breaktryWord = tryWord[1:]my_stack.append(tryWord)line = line[0:len(line) - len(tryWord)]len_hang = len(line)while len(my_stack):t = my_stack.pop()if t == '\n':h.write('\n')else:print(t)h.write(t + " ")h.close()if __name__ == '__main__':print('獲取字典')dic = get_dic(train_data)print('開始匹配……')RMM(test_data,result_data,dic)

    3.3 統(tǒng)計分詞

    • 主要操作

      • 建立統(tǒng)計語言模型;
      • 對句子進行單詞劃分,然后對劃分結(jié)果進行概率計算,獲得概率最大額分詞方式,常用統(tǒng)計學(xué)習(xí)算法有隱含馬爾可夫(HMM)、條件隨機場(CRF)等;
    • n元條件概率

    P(wi∣wi?(n?1),…,wi?1)=count(wi?(n?1),…,wi?1,wi)count(wi?(n?1),…,wi?1)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})}P(wi?wi?(n?1)?,,wi?1?)=count(wi?(n?1)?,,wi?1?)count(wi?(n?1)?,,wi?1?,wi?)?

    其中,count(wi?(n?1),…,wi?1)count(w_{i-(n-1)},…,w_{i-1})count(wi?(n?1)?,,wi?1?)表示詞wi?(n?1),…,wi?1w_{i-(n-1)},…,w_{i-1}wi?(n?1)?,,wi?1?在語料庫中出現(xiàn)的總次數(shù);

    • HMM模型

      將分詞作為字在字串中的序列標注任務(wù)來實現(xiàn)。基本思路:每個字在構(gòu)造一個特定的詞語時都占據(jù)著一個確定的構(gòu)詞位置(即詞位),規(guī)定每個字最多有四個構(gòu)詞位置:B(詞首)、M(詞中)、E(詞尾)、S(單獨成詞);

  • 數(shù)學(xué)理論

    假設(shè)用λ=λ1λ2…λn\lambda=\lambda _1 \lambda_2 …\lambda_nλ=λ1?λ2?λn?代表輸入的句子,nnn表示句子長度,λi\lambda_iλi?表示字,o=o1o2…ono=o_1o_2…o_no=o1?o2?on?表示輸出的標簽,則理想輸出為:

  • max=maxP(o=o1o2…on∣λ=λ1λ2…λn)=P(o1∣λ1)P(o2∣λ2)…P(on∣λn)max = maxP(o=o_1o_2…o_n|\lambda=\lambda _1 \lambda_2 …\lambda_n)=P(o_1|\lambda_1)P(o_2|\lambda_2)…P(o_n|\lambda_n)max=maxP(o=o1?o2?on?λ=λ1?λ2?λn?)=P(o1?λ1?)P(o2?λ2?)P(on?λn?)

    在這個算法中,求解結(jié)果的常用方法是Veterbi算法,這是一種動態(tài)規(guī)劃算法,核心是:如果最終的最優(yōu)路徑經(jīng)過某個節(jié)點oio_ioi?,則從初始節(jié)點到oi?1o_{i-1}oi?1?點的路徑必然也是一個最優(yōu)路徑,因為每個節(jié)點oio_ioi?只會影響前后兩個P(oi?1∣oi)P(o_{i-1}|o_i)P(oi?1?oi?)P(oi∣oi+1)P(o_i|o_{i+1})P(oi?oi+1?)

  • Python實現(xiàn)
  • #!/usr/bin/env python # -*- coding: utf-8 -*- # @version : 1.0 # @Time : 2019-8-27 15:42 # @Author : cunyu # @Email : cunyu1024@foxmail.com # @Site : https://cunyu1943.github.io # @File : HMM_model.py # @Software: PyCharm # @Desc : HMM模型分詞import os import pickleclass HMM(object):def __init__(self):import os# 主要是用于存取算法中間結(jié)果,不用每次都訓(xùn)練模型self.model_file = './data/models/hmm_model.pkl'# 狀態(tài)值集合self.state_list = ['B', 'M', 'E', 'S']# 參數(shù)加載,用于判斷是否需要重新加載model_fileself.load_para = False# 用于加載已計算的中間結(jié)果,當需要重新訓(xùn)練時,需初始化清空結(jié)果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:# 狀態(tài)轉(zhuǎn)移概率(狀態(tài)->狀態(tài)的條件概率)self.A_dic = {}# 發(fā)射概率(狀態(tài)->詞語的條件概率)self.B_dic = {}# 狀態(tài)的初始概率self.Pi_dic = {}self.load_para = False# 計算轉(zhuǎn)移概率、發(fā)射概率以及初始概率def train(self, path):# 重置幾個概率矩陣self.try_load_model(False)# 統(tǒng)計狀態(tài)出現(xiàn)次數(shù),求p(o)Count_dic = {}# 初始化參數(shù)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 += 1print(line)line = 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 # 每個句子的第一個字的狀態(tài),用于計算初始狀態(tài)概率else:self.A_dic[line_state[k - 1]][v] += 1 # 計算轉(zhuǎn)移概率self.B_dic[line_state[k]][word_list[k]] = \self.B_dic[line_state[k]].get(word_list[k], 0) + 1.0 # 計算發(fā)射概率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 selfdef viterbi(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 = {}# 檢驗訓(xùn)練的發(fā)射概率矩陣中是否有該字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 # 設(shè)置未知字單獨成詞(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])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')print('訓(xùn)練完成')text = input('輸入一個句子:')result = hmm.cut(text)print(str(list(result)))
    • 其他統(tǒng)計分詞算法

      • 條件隨機場(CRF)
      • 神經(jīng)網(wǎng)絡(luò)分詞算法(CNN、LSTM)

    3.5 中文分詞工具——Jieba

    • 使用Jieba的優(yōu)點

      • 社區(qū)活躍
      • 功能豐富
      • 使用簡單
      • 提供多種編程語言實現(xiàn)
    • 官網(wǎng)地址

    • 簡介

      結(jié)合基于規(guī)則和統(tǒng)計的兩類方法,首先基于前綴詞典(指詞典中的詞按照前綴包含的順序排列)進行詞圖掃描,從而形成一種層級包含結(jié)構(gòu)。這樣可以快速構(gòu)建包含全部可能分詞結(jié)果的有向無環(huán)圖,圖中包含多條分詞路徑,有向指全部路徑都始于第一個字、止于最后一個字,而無環(huán)則指節(jié)點間不構(gòu)成閉環(huán)。基于標注語料,使用動態(tài)規(guī)劃方法找出最大概率路徑并將其作為最終分詞結(jié)果。而對于OOV,則使用基于漢字成詞的HMM模型,采用Viterbi算法進行推導(dǎo)。

    • 三種分詞模式

      • 精確模式:試圖將句子最精確的切分,適合文本分析;
      • 全模式:將句子中所有可以成詞的詞語都掃描出來,速度快,但存在歧義問題;
      • 搜索引擎模式:在精確模式的基礎(chǔ)上,多長詞再切分,提高召回率,適用于搜索引擎分詞;
    #!/usr/bin/env python # -*- coding: utf-8 -*- # @version : 1.0 # @Time : 2019-8-26 21:33 # @Author : cunyu # @Email : cunyu1024@foxmail.com # @Site : https://cunyu1943.github.io # @File : jieba_demo.py # @Software: PyCharm # @Desc : jieba簡單使用# 三種模式對比import jieba sent = '中文分詞是文本處理中不可獲取的一步!'seg_list = jieba.cut(sent,cut_all=True) print('全模式: ', '/'.join(seg_list))seg_list = jieba.cut(sent,cut_all=False) print('精確模式: ', '/'.join(seg_list))seg_list = jieba.cut_for_search(sent) print('搜索引擎模式: ', '/'.join(seg_list))

    • 高頻詞提取

      高頻詞指文檔中出現(xiàn)頻率較高且非無用的詞語,在一定程度上代表了文檔的焦點所在,主要有以下干擾:

      • 標點符號
      • 停用詞
    #!/usr/bin/env python # -*- coding: utf-8 -*- # @version : 1.0 # @Time : 2019-8-27 9:16 # @Author : cunyu # @Email : cunyu1024@foxmail.com # @Site : https://cunyu1943.github.io # @File : keyWords.py # @Software: PyCharm # @Desc : 關(guān)鍵詞抽取import glob import random import jieba# 讀取文件 def get_content(path):with open(path, 'r', encoding='gbk', errors='ignore') as f:content = ''for l in f:l = l.strip()content += lreturn content# 獲取高頻詞 def get_TF(words, topK=10):tf_dic = {}for w in words:tf_dic[w] = tf_dic.get(w, 0) + 1return sorted(tf_dic.items(), key=lambda x: x[1], reverse=True)[:topK]# 加載停用詞 def stop_words(path):with open(path) as f:return [l.strip() for l in f]# 分詞 def main(path,stop_words_path):files = glob.glob(path)corpus = [get_content(x) for x in files[:5]]# 隨機產(chǎn)生一個隨機數(shù)(小于總的長度)個樣本,然后對這幾個樣本進行提取高頻詞操作sample_inxs = random.randint(0, len(corpus))for sample_inx in range(sample_inxs):split_words = [x for x in jieba.cut(corpus[sample_inx]) if x not in stop_words(stop_words_path)]print('樣本之一:' + corpus[sample_inx])print('樣本分詞效果:' + '/ '.join(split_words))print('樣本的topK(10)詞:' + str(get_TF(split_words)))if __name__ == '__main__':path = './data/news/C000010/*.txt'stop_words_path='./data/stop_words.utf8'main(path, stop_words_path)

    總結(jié)

    以上是生活随笔為你收集整理的自然语言处理系列之:中文分词技术的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。