字典树实现_学习NLP的第3天——字典树
通過《自然語言處理入門》(何晗)的第2章來學(xué)習(xí)一下分詞的常用算法,因此以下的實現(xiàn)方法都是通過HanLP實現(xiàn)的。這里主要記錄我在學(xué)習(xí)過程中整理的知識、調(diào)試的代碼和心得理解,以供其他學(xué)習(xí)的朋友參考。
字符串集合常用字典樹(Trie樹)存儲,這是一種字符串上的樹形數(shù)據(jù)結(jié)構(gòu)。
字典樹中每條邊都對應(yīng)一個字,從根節(jié)點往下的路徑構(gòu)成一個個字符串。字典樹并不直接在節(jié)點上存儲字符串,而是將詞典視作根節(jié)點到某節(jié)點之間的一條路徑,并在終點節(jié)點上做個“該節(jié)點對應(yīng)詞語的結(jié)尾”的標(biāo)記。
字符串是一條路徑,要查詢一個單詞,只需順著這條路徑從歸根節(jié)點往下走。如果能走到特殊標(biāo)記的節(jié)點,則說明該字符串在集合中,否則說明不存在。
圖片來自《自然語言處理入門》(何晗)
例如,上圖中的藍色標(biāo)記著該節(jié)點是一個詞的結(jié)尾,數(shù)字是認為的編號。如“入門”、“自然人”等結(jié)束節(jié)點為藍色的路徑都可以成為詞,而“自然語”等結(jié)束節(jié)點為白色的路徑則不能成為詞。
字典樹的節(jié)點實現(xiàn)
每個節(jié)點都應(yīng)該知道自己的子節(jié)點與對應(yīng)的邊,以及自己是否對應(yīng)一個詞。
我們用None來表示該節(jié)點不對應(yīng)詞語。
節(jié)點的Python實現(xiàn)如下:
class Node(object): def __init__(self, value): self._children = {} # 子節(jié)點存儲變量 self._value = value # 當(dāng)前節(jié)點的值 def _add_child(self, char, value, overwrite=False): child = self._children.get(char) if child is None: # 判斷當(dāng)前節(jié)點是否已經(jīng)存在字符char對應(yīng)的child child = Node(value) self._children[char] = child elif overwrite: # 根據(jù)overwrite判斷是否覆蓋child的值 child._value = value return child字典樹的增刪改查實現(xiàn)
只要將以上節(jié)點連到根節(jié)點上,就得到了字典樹。根節(jié)點繼承自普通節(jié)點,并增加了一些面向用戶的公開方法。因此,只要拿到根節(jié)點,就能抓住整棵字典樹。
從確定有限狀態(tài)自動機(DFA)的角度來講,每個節(jié)點都是一個狀態(tài),狀態(tài)表示當(dāng)前已查詢到的前綴。
有限狀態(tài)自動機(DFA)
有限狀態(tài)自動機(deterministic finite automaton, DFA)是一個能實現(xiàn)狀態(tài)轉(zhuǎn)移的自動機。對于一個給定的屬于該自動機的狀態(tài)和一個屬于該自動機字母表Σ的字符,它都能根據(jù)事先給定的轉(zhuǎn)移函數(shù)轉(zhuǎn)移到下一個狀態(tài)(這個狀態(tài)可以是先前那個狀態(tài))。每次輸入都會引起狀態(tài)的改變或者不變。
字典樹的Python實現(xiàn)如下:
class Trie(Node): def __init__(self): super().__init__(None) def __contains__(self, key): return self[key] is not None def __getitem__(self, key): state = self for char in key: # 遍歷字符串中的每一個字符 state = state._children.get(char) # 一直依據(jù)路徑找到目標(biāo)詞 if state is None: return None return state._value def __setitem__(self, key, value): state = self for i, char in enumerate(key): # 枚舉字符串中的每一個字符及其位置坐標(biāo) if i < len(key) - 1: # 若當(dāng)前詞不是結(jié)尾詞 state = state._add_child(char, None, False) else: # 若當(dāng)前詞是結(jié)尾詞 state = state._add_child(char, value, True)運行測試
我們參考書中方法對以上的字典樹做如下測試:
if __name__ == '__main__': trie = Trie() # 增 trie['自然'] = 'nature' trie['自然人'] = 'human' trie['自然語言'] = 'language' trie['自語'] = 'talkto oneself' trie['入門'] = 'introduction' print(trie['自然']) # 刪 trie['自然'] = None print(trie['自然']) # 改 print(trie['自然語言']) trie['自然語言'] = 'human language' print(trie['自然語言'])運行結(jié)果
natureNonelanguagehuman language字典樹的使用是為了提高字典的查詢速度,優(yōu)化分詞算法的效率。
本文使用教材:《自然語言處理入門》(何晗):2.4.1 - 2.4.3
本文中代碼大部分引自該書中的代碼
總結(jié)
以上是生活随笔為你收集整理的字典树实现_学习NLP的第3天——字典树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bio nio aio区别_8分钟深入浅
- 下一篇: Keychron Q12 机械键盘亮相: