1. 程式人生 > >支援中文的基於詞為基本粒度的字首樹(prefix trie)python實現

支援中文的基於詞為基本粒度的字首樹(prefix trie)python實現

Trie樹,也叫字典樹、字首樹。可用於”predictive text”和”autocompletion”,亦可用於統計詞頻(邊插入Trie樹邊更新或新增詞頻)。

電腦科學中,trie,又稱字首樹字典樹,是一種有序,用於儲存關聯陣列,其中的鍵通常是字串。與二叉查詢樹不同,鍵不是直接儲存在節點中,而是由節點在樹中的位置決定。一個節點的所有子孫都有相同的字首,也就是這個節點對應的字串,而根節點對應空字串。一般情況下,不是所有的節點都有對應的值,只有葉子節點和部分內部節點所對應的鍵才有相關的值。

#!/usr/bin/python
# -*- coding:utf-8 -*-
# * trie, prefix tree, can be used as a dict
# * author: 
[email protected]
import sys reload(sys) sys.setdefaultencoding("utf-8") # Singleton sentinel - works with pickling class NULL(object): pass class Node: def __init__(self, value = NULL): self.value = value self.children = {} class Trie(object): def __init__(self): self.root = Node() def insert(self, key, value = None, sep = ' '): # key is a word sequence separated by 'sep' elements = key if isinstance(key, list) else key.split(sep) node = self.root for e in elements: if not e: continue if e not in node.children: child = Node() node.children[e] = child node = child else: node = node.children[e] node.value = value def get(self, key, default = None, sep = ' '): elements = key if isinstance(key, list) else key.split(sep) node = self.root for e in elements: if e not in node.children: return default node = node.children[e] return default if node.value is NULL else node.value def delete(self, key, sep = ' '): elements = key if isinstance(key, list) else key.split(sep) return self.__delete(elements) def __delete(self, elements, node = None, i = 0): node = node if node else self.root e = elements[i] if e in node.children: child_node = node.children[e] if len(elements) == (i+1): if child_node.value is NULL: return False # not in dict if len(child_node.children) == 0: node.children.pop(e) else: child_node.value = NULL return True elif self.__delete(elements, child_node, i+1): if len(child_node.children) == 0: return node.children.pop(e) return True return False def shortest_prefix(self, key, default = NULL, sep = ' '): elements = key if isinstance(key, list) else key.split(sep) results = [] node = self.root value = node.value for e in elements: if e in node.children: results.append(e) node = node.children[e] value = node.value if value is not NULL: return sep.join(results) else: break if value is NULL: if default is not NULL: return default else: raise Exception("no item matches any prefix of the given key!") return sep.join(results) def longest_prefix(self, key, default = NULL, sep = ' '): elements = key if isinstance(key, list) else key.split(sep) results = [] node = self.root value = node.value for e in elements: if e not in node.children: if value is not NULL: return sep.join(results) elif default is not NULL: return default else: raise Exception("no item matches any prefix of the given key!") results.append(e) node = node.children[e] value = node.value if value is NULL: if default is not NULL: return default else: raise Exception("no item matches any prefix of the given key!") return sep.join(results) def longest_prefix_value(self, key, default = NULL, sep = ' '): elements = key if isinstance(key, list) else key.split(sep) node = self.root value = node.value for e in elements: if e not in node.children: if value is not NULL: return value elif default is not NULL: return default else: raise Exception("no item matches any prefix of the given key!") node = node.children[e] value = node.value if value is not NULL: return value if default is not NULL: return default raise Exception("no item matches any prefix of the given key!") def longest_prefix_item(self, key, default = NULL, sep = ' '): elements = key if isinstance(key, list) else key.split(sep) node = self.root value = node.value results = [] for e in elements: if e not in node.children: if value is not NULL: return (sep.join(results), value) elif default is not NULL: return default else: raise Exception("no item matches any prefix of the given key!") results.append(e) node = node.children[e] value = node.value if value is not NULL: return (sep.join(results), value) if default is not NULL: return (sep.join(results), default) raise Exception("no item matches any prefix of the given key!") def __collect_items(self, node, path, results, sep): if node.value is not NULL: results.append((sep.join(path), node.value)) for k, v in node.children.iteritems(): path.append(k) self.__collect_items(v, path, results, sep) path.pop() return results def items(self, prefix, sep = ' '): elements = prefix if isinstance(prefix, list) else prefix.split(sep) node = self.root for e in elements: if e not in node.children: return [] node = node.children[e] results = [] path = [prefix] self.__collect_items(node, path, results, sep) return results def keys(self, prefix, sep = ' '): items = self.items(prefix, sep) return [key for key,value in items] if __name__ == '__main__': trie = Trie() trie.insert('happy 站臺', 1) trie.insert('happy 站臺 xx', 10) trie.insert('happy 站臺 xx yy', 11) trie.insert('happy 站臺 美食 購物 廣場', 2) trie.insert('sm') trie.insert('sm 國際', 22) trie.insert('sm 國際 廣場', 2) trie.insert('sm 城市廣場', 3) trie.insert('sm 廣場', 4) trie.insert('sm 新生活 廣場', 5) trie.insert('sm 購物 廣場', 6) trie.insert('soho 尚都', 3) print trie.get('sm') print trie.longest_prefix([], default="empty list") print trie.longest_prefix('sm') print trie.shortest_prefix('happy 站臺') print trie.shortest_prefix('happy 站臺 xx') print trie.shortest_prefix('sm') print trie.longest_prefix('sm xx', sep = '&', default = None) print 'sm 廣場 --> ', trie.get('sm 廣場') print trie.get('sm 廣場'.split(' ')) print trie.get('神馬') print trie.get('happy 站臺') print trie.get('happy 站臺 美食 購物 廣場') print trie.longest_prefix('soho 廣場', 'default') print trie.longest_prefix('soho 尚都 廣場') print trie.longest_prefix_value('soho 尚都 廣場') print trie.longest_prefix_value('xx 尚都 廣場', 90) print trie.longest_prefix_value('xx 尚都 廣場', 'no prefix') print trie.longest_prefix_item('soho 尚都 廣場') print '============== keys =================' print 'prefix "sm": ', ' | '.join(trie.keys('sm')) print '============== items =================' print 'prefix "sm": ', trie.items('sm') print '================= delete =====================' print trie.delete('sm 廣場') print trie.get('sm 廣場') print trie.delete('sm 國際') print trie.get('sm 國際') print trie.delete('sm xx') print trie.delete('xx') print '====== no item matches any prefix of given key ========' print trie.longest_prefix_value('happy') print trie.longest_prefix_value('soho xx')

執行結果:

None
empty list
sm
happy 站臺
happy 站臺
sm
None
sm 廣場 -->  4
4
None
1
2
default
soho 尚都
3
90
no prefix
('soho \xe5\xb0\x9a\xe9\x83\xbd', 3)
============== keys =================
prefix "sm":  sm | sm 新生活 廣場 | sm 城市廣場 | sm 廣場 | sm 購物 廣場 | sm 國際 | sm 國際 廣場
============== items =================
prefix "sm":  [('sm', None), ('sm \xe6\x96\xb0\xe7\x94\x9f\xe6\xb4\xbb \xe5\xb9\xbf\xe5\x9c\xba', 5), ('sm \xe5\x9f\x8e\xe5\xb8\x82\xe5\xb9\xbf\xe5\x9c\xba', 3), ('sm \xe5\xb9\xbf\xe5\x9c\xba', 4), ('sm \xe8\xb4\xad\xe7\x89\xa9 \xe5\xb9\xbf\xe5\x9c\xba', 6), ('sm \xe5\x9b\xbd\xe9\x99\x85', 22), ('sm \xe5\x9b\xbd\xe9\x99\x85 \xe5\xb9\xbf\xe5\x9c\xba', 2)]
================= delete =====================
True
None
True
None
False
False
====== no item matches any prefix of given key ========
Traceback (most recent call last):
  File "./word_based_trie.py", line 225, in <module>
    print trie.longest_prefix_value('happy')
  File "./word_based_trie.py", line 128, in longest_prefix_value
    raise Exception("no item matches any prefix of the given key!")
Exception: no item matches any prefix of the given key!


相關推薦

支援中文基於基本粒度字首prefix triepython實現

Trie樹,也叫字典樹、字首樹。可用於”predictive text”和”autocompletion”,亦可用於統計詞頻(邊插入Trie樹邊更新或新增詞頻)。 在電腦科學中,trie,又稱字首樹或字典樹,是一種有序樹,用於儲存關聯陣列,其中的鍵通常是字串。與二叉查詢

支持中文基於基本粒度的前綴prefix triepython實現

情況 key -s path join ret int blank ref Trie樹,也叫字典樹、前綴樹。可用於”predictive text”和”autocompletion”。亦可用於統計詞頻(邊插入Trie樹邊更新或加入詞頻)。 在計算機科學中。

《機器學習》 周志華學習筆記第六章 支援向量機課後習題python 實現

一、 1.間隔與支援向量 2.對偶問題 3.核函式 xi與xj在特徵空間的內積等於他們在原始yangben空間中通過函式k(.,.)計算的結果。 核矩陣K總是半正定的。 4.軟間隔與正則化 軟間隔允許某些samples不滿足約束  鬆弛變數 5.支援

多執行緒技術模擬平行計算之二:陣列字首Prefix Sum

一、字首和(Prefix Sum)定義: 給定一個數組A[1..n],字首和陣列PrefixSum[1..n]定義為:PrefixSum[i] = A[0]+A[1]+...+A[i-1]; 例如:A[5,6,7,8] --> PrefixSum[5,11,18,26

全文檢索技術學習(三)——Lucene支援中文

分析器(Analyzer)的執行過程 如下圖是語彙單元的生成過程: 從一個Reader字元流開始,建立一個基於Reader的Tokenizer分詞器,經過三個TokenFilter生成語彙單元Token。 要看分析器的分析效果,只需要看TokenStr

中文基本原理以及jieba分的用法

結巴分詞是國內程式設計師用Python開發的一箇中文分詞模組,可能是最好的Python中文分片語件? 中文分詞的原理 – 1、中文分詞(Chinese Word Segmentation) 指的是將一個漢字序列切分成一個一個單獨的詞。分詞就是將連續的

敏感過濾演算法:字首演算法

背景 平時我們在逛貼吧、牛客網的時候,我們經常可以看到一些形如 “***”的符號,通過上下文,我們也可以很容易猜到這些詞原來是罵人的話,只是被系統和諧了。那麼這是如何實現的呢?作為普通人,我們最先想到的一種辦法就是把所有敏感串存入一個列表中,然後使用者每發一條內容後臺就把該內容與敏感串列表

將句子表示向量基於監督學習的句子表示學習sentence embedding

類型 過多 並且 通過 輸入 集合 學習 不一定 論壇 1. 引言 上一篇介紹了如何用無監督方法來訓練sentence embedding,本文將介紹如何利用監督學習訓練句子編碼器從而獲取sentence embedding,包括利用釋義數據庫PPDB、自然語言推理數據SN

mysql5.7:mysql安裝和基於SSL加密的主從復制詳細剖析

mysql ssl db 數據 加密傳輸 小生博客:http://xsboke.blog.51cto.com 小生 Q Q:1770058260 -------謝謝您的參考,如有疑問,歡迎交流目錄:--------my

08.SQL Server 基本操作【分離脫機、附加聯機

原因 -1 文件的操作 刪除 方法 附加 文件 技術分享 屬性 1、創建、刪除(對準數據庫右鍵)2、分離(脫機)、附加(聯機) 關於附加數據庫失敗的處理:原因:對文件的操作權限不夠處理方法:對準mdf文件和ldf文件 右鍵 屬性 安全性將 用戶 Users

git —— 基本命令以及操作No.1

src del 刪除 blog -1 comm commit 操作 提交 git基本命令(附加描述) 1.把文件添加到暫存區$ git add readme.txt 2.把暫存區的文件文件添加到倉庫$ git commit -m "提交說明" 備註:add添加單個文

基於 MySQL 的數據庫實踐更名運算

AI 方法 希望 log Go 最低工資 HERE 笛卡爾 clas 考慮下面的查詢查詢。 select name, course_id from instructor, teaches where instructor.ID = teaches.ID; 它的結果是一個具有

基於zk的分布幸運28源碼下載式鎖leader選舉實現

rest logger 接口 ets abstract 問題 .get single created 做了幸運28源碼下載論壇:haozbbs.com Q1446595067 兩版實現,先是直接用zk的接口做的,後來又用curator做了個。主要是用來在集群環境中確定一個主

編程基本的命名規範記錄一下

約定 編程 png img ima 技術 描述 image 變量 1、命名規則約定: 2.匈牙利命名法: 變量名=屬性+類型+對象描述 2.1屬性命名規則 2.2關鍵字母組合 編程基本的命名規範(記錄一下)

基於分解的多目標進化演算法MOEA/D

目錄 1、MOEA/D的特點 2、 MOEA/D的分解策略 3、MOEA/D的流程 基於分解的多目標進化演算法(Multi-objectiveEvolutionary Algorithm Based on Decomposition, MOEA/D)將多目標優化問題被轉

leetcode-將有序陣列轉換二叉搜尋JavaScript

將一個按照升序排列的有序陣列,轉換為一棵高度平衡二叉搜尋樹。 本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。 示例: 給定有序陣列: [-10,-3,0,5,9], 一個可能的答案是:[0,-3,9,-10,null,5],它可以

用模擬器載入基於ARM平臺的WinCE6 0 核心NK bin

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

python中使用opencv將RGB影象轉換HSV及YCrCb影象附程式碼

【時間】2018.11.01 【題目】在python中使用opencv將RGB影象轉換為HSV及YCrCb影象(附程式碼) 目錄 概述 一、程式碼實現 二、執行結果 三、關於HSV及YCrCb的一點補充 3.1HSV顏色空間 3.2 YCRCBA顏色空間

課設 - 基於微控制器的溫控報警系統設計 電路+程式

  本設計所介紹的數字溫度計與傳統的溫度計相比,具有讀數方便,測溫範圍廣,測溫準確,其輸出溫度採用數字顯示,主要用於對測溫比較準確的場所,或科研實驗室使用,該設計控制器使用微控制器AT89S51,測溫感測器使用DS18B20,用3位共陽極LED數碼管以串列埠傳送資料,實現溫度顯示,

SRPG遊戲開發三十三第八章 遊戲中的資料 - 三 編輯器做準備Editors Preparation

返回總目錄 第八章 遊戲中的資料(Data in Game) 在之前的章節中,我們進行地圖物件的生成,移動等操作。 這一章本來可以進行戰鬥的編寫,不過資料缺失是一個問題。 所以這一章我們先來建立一些資料,以及如何編輯它們,是否需要生成配置檔案等。 文章