N-Gram+最短路徑分詞

PS:這篇文章中的代碼,僅為一個簡單的DEMO,并未進行過代碼和算法的優化,參數也未進行過調整,僅僅是演示了一個從訓練模型到應用的完整過程

簡介

關于這種分詞方法,網上的相關文章已經是相當相當少了,最出名的就是NLPIR分詞中采用了這種方法(貌似最早也是這個分詞工具的作者提出的)

相關文章

自然語言處理中的N-Gram模型詳解
自然語言處理中N-Gram模型的Smoothing算法
HanLP作者對N-ShortPath分詞理解的一個簡單介紹
呂震宇先生對NLPIR分詞的理解(這些文章里有些地方暫時持保留意見,或者說對于這個分詞算法本身就有很多疑問)

代碼

from nltk.util import bigrams, trigrams
from nltk.text import Text
from nltk import FreqDist
from functools import reduce
from bidict import bidict
import numpy as np

corpus = [
    '<begin> 小鳥 聲音 不大 , 卻 句 句 在理 , 全場 都 靜靜 恭聽。 <end>',
    '<begin> 他 說 : “ 神 是否 創造 世界 ,即 神 對 世界 的 關系 如何 ,這個 問題 其實 就是 關于 精神 對 感性 一般 或 抽象 對 實在、類 對 個體 的 關系 如何 的 問題 ;這個 問題 是 屬于 人類 認識 和 哲學 上 最 重要 又 最 困難 的 問題 之一 , 整個 哲學史 其實 只在 這個 問題 周圍 繞 圈子 , 古代 哲學 中 斯多葛派 和 伊壁鳩魯派 間 、 柏拉圖派 和 亞里士多德派 間 、 懷疑派 和 獨斷派 間 的 爭論 , 中古哲學 中 唯名論者 和 實在論者 間 的 爭論 , 以及 近代 哲學 中 唯心主義者 和 實在論者 或 經驗主義者 間 的 爭論 , 歸根結底 都是 關于 這個 問題 。 <end>”',
    '<begin> 討論 法 的 本位 問題 , 應該 局限 于 實在 法效 用 的 實現 借助 于 何種 規范 手段 的 范圍 內 , 它 主要 應 討論 " 法 是 什么 " 的 問題 , 而 不是 " 法 應當 是 什么 " 的 問題 。 <end>',
    '<begin> 現在 , 你 已是 全班 第一名 了 , 我們 都要 向 你 學習 , 我們 還會 繼續 幫助 你 。 <end>',
    '<begin> 他們 的 罪惡 行徑 也 從 反面 教育 我們 , 革命 的 政治工作 對于 我們 黨 的 各項 工作 , 對于 我們 軍隊 和 人民 來說 , 確實 是 不可以 須臾 離開 的 生命線 。 <end>',
    '<begin> 從 研究系 辦 的 刊物 來看 , 確實 登載 過 大量 的 討論 社會主義 的 文章 , 似乎 亦 擁護 社會主義 , 但 實際上 這 只是 假象 。 <end>',
    '<begin> 他 那些 舞臺 下 、 劇場 外 的 事 的確 是 鮮為人知 的 。 <end>',
    # '<begin> 他 說 的 確實 在理 <end>'
]

# 單字切分,暫時沒用到
def atomic_split(param1, param2):
    if isinstance(param1, list):
        return param1 + list(param2.replace(' ', ''))
    else:
        return atomic_split(atomic_split([], param1), param2)


atomics = reduce(atomic_split, corpus)

#對語料的切分
def word_split(param1, param2):
    if isinstance(param1, list):
        return param1 + param2.split()
    else:
        return word_split(word_split([], param1), param2)


words = reduce(word_split, corpus)

#計算詞頻,索引
fd = FreqDist(words)

index = bidict()
pos = 0
for k, c in fd.items():
    index[k] = pos
    pos = pos + 1

#=====利用nltk的biggrams函數,建立gram矩陣==========================
grams = list(bigrams(words))

gc = np.zeros((fd.B(), fd.B()), dtype=np.int32)

#統計gram次數
for p1, p2 in grams:
    gc[index[p1], index[p2]] += 1

#統計gram概率
gp = np.zeros((fd.B(), fd.B()))


#平滑系數
ratio = 0.9

for row in range(0, fd.B()):
    for col in range(0, fd.B()):
        gp[row, col] = ratio * (gc[row, col] / fd[index.inv[row]]) + (
            1 - ratio) * (fd[index.inv[col]] / len(words))

#======================模型訓練完成=================================

#=============求最短路徑(非N-最短路徑,算法和原方法不同,一個是因為對原算法有疑問,另一個為了快速完成DEMO)==================
def split(s, pos=0):
    if len(s) <= pos: return [{'key': '<end>'}]
    result = []
    for k in fd.keys():
        end = pos + len(k)
        if len(k) > 1 and end <= len(s) and k == s[pos:end]:

            result.append({'key': k, 'childs': split(s, end)})

    result.append({'key': s[pos:pos + 1], 'childs': split(s, pos + 1)})

    return result


def split_to_tree(s):
    return {'key': '<begin>', 'childs': split(input)}


def segment(node):
    k = node['key']
    childs = node.get('childs')

    if not childs:
        return

    i1 = index.get(k)
    for child in childs:
        i2 = index.get(child['key'])
        child['score'] = gp[i1, i2] if (i1 and
                                        i2) else (1 - ratio) * 1 / len(words)
        segment(child)


def shortest(node):
    childs = node.get("childs")
    score = node.get('score', 0)
    key = node.get('key')

    if not childs:
        return score, [key]

    current_score, current_seq = -1, []
    for child in childs:
        _score, _seq = shortest(child)
        if _score > current_score:
            current_score, current_seq = _score, _seq

    return current_score + score, [key] + current_seq


#================分詞函數完成=================

input = '他說的確實在理'

# 將輸入轉化成tree
root = split_to_tree(input)
# 根據上面的gram概率模型,計算得分
segment(root)

#求最大得分
score, seq = shortest(root)
print(seq, score)
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容