關於局部敏感哈希算法。以前用R語言實現過,但是因爲在R中效能過低。因而放棄用LSH來作相似性檢索。學了python發現很是多模塊都能實現,而且經過隨機投影森林讓查詢數據更快。以爲可以試試大規模應用在數據相似性檢索+去重的場景。css
私以爲,文本的相似性可以分爲兩類:一類是機械相似性;一類是語義相似性。
機械相似性表明着,兩個文本內容上的相關程度。比方「你好嗎」和「你好」的相似性。純粹表明着內容上字符是否全然共現,應用場景在:文章去重;
語義相似性表明着,兩個文本語義上的相似程度。比方「蘋果」和「公司」的相似性。本篇不作這一討論html
以前寫關於R語言實現的博客:
R語言實現︱局部敏感哈希算法(LSH)解決文本機械相似性的問題(一,基本原理)
R語言實現︱局部敏感哈希算法(LSH)解決文本機械相似性的問題(二。textreuse介紹)python
機械相似性python版的四部曲:
LSH︱python實現局部敏感隨機投影森林——LSHForest/sklearn(一)
LSH︱python實現局部敏感哈希——LSHash(二)
相似性︱python+opencv實現pHash算法+hamming距離(simhash)(三)
LSH︱python實現MinHash-LSH及MinHash LSH Forest——datasketch(四)
.算法
本節參考:論文《基於隨機投影的場景文本圖像聚類方法研究》與博客 隨機投影森林-一種近似近期鄰方法(ANN) 數組
當數據個數比較大的時候,線性搜索尋找KNN的時間開銷太大,而且需要讀取所有的數據在內存中,這是不現實的。所以,實際project上,使用近似近期鄰也就是ANN問題。
當中一種方法是利用隨機投影樹,對所有的數據進行劃分,將每次搜索與計算的點的數目減少到一個可接受的範圍,而後創建多個隨機投影樹構成隨機投影森林,將森林的綜合結果做爲終於的結果。bash
創建一棵隨機投影樹的過程大體例如如下(以二維空間爲例):markdown
在數學計算上。是經過計算各個點與垂直向量的點積完畢這一步驟的,點積大於零的點劃分到左子樹,點積小於零的點劃分到右子樹。數據結構
注意一點。圖中不帶箭頭的直線是用於劃分左右子樹的根據,帶箭頭的向量是用於計算點積的。這樣,原有的點就劃分爲了兩部分,圖比例如如下:
但是此時一個劃分結果內的點的數目仍是比較多。所以繼續劃分。再次隨機選取一個向量。與該向量垂直的直線將所有點進行了劃分。圖比例如如下:
注意一點,此時的劃分是在上一次劃分的基礎上進行的。app
也就是說現在圖中的點已經被劃分紅了四部分,相應於一棵深度爲2。有四個葉節點的樹。dom
以此類推繼續劃分下去,直到每個葉節點中點的數目都達到一個足夠小的數目。
注意這棵樹並不是全然樹。
隨機投影森林的創建需要兩個參數。即單棵樹的深度 + 森林數量。
這兩個參數決定了數據集的分散程度以及隨機投影后獲得的向量維數。
利用這棵樹對新的點進行近期鄰計算時,首先經過計算該點與每次劃分所用向量的點積。來找到其所屬於的葉節點,而後利用這個葉節點內的這些點進行近期鄰算法的計算。
這個過程是一棵隨機投影樹的計算過程。利用相同的方法。創建多個隨機投影樹構成隨機森林,將森林的總和結果做爲終於的結果。
.
Wright等人 已將隨機投影的方法應用於視角變化的人臉識別,Nowak等人 採用隨機投影的方法學習視覺詞的相似度度量。Freund等人將隨機投影應用於手寫體識別上,取得了很是好的效果。
.
論文《基於隨機投影的場景文本圖像聚類方法研究》中,將每個葉子節點當成一維特徵,用葉子節點的特徵點個數做爲葉子節點的描寫敘述,最後獲得測試圖像的特徵向量。
有點相似word2vec之中的霍夫曼樹。
論文中的實驗結果:
當中。森林規模10棵。
而K-means
聚類是屢次實驗不一樣的迭代次數與類別數,以最好的聚類結果做爲終於結果
因而可知。ASIFT比SIFT對天然場景下的文本區域圖像的局部特徵描寫敘述更好更準確。這是因爲SIFT僅僅是具備尺度和旋轉不變性。對於具備視角變化的相同文字卻沒法獲得匹配描寫敘述。而ASIFT不只對圖像具備尺度旋轉不變性,還具備仿射不變性,這樣的特性對天然場景下的文本處理有更好的有用性。
具體的ASIFT與SIFT對照可見論文。
.
LSHforest=LSH+隨機投影樹
在python的sklearn中有LSHForest可以實現。
class sklearn.neighbors.LSHForest(n_estimators=10, radius=1.0, n_candidates=50, n_neighbors=5, min_hash_match=4, radius_cutoff_ratio=0.9, random_state=None)
隨機投影森林是近期鄰搜索方法的一種替代方法。
LSH森林數據結構使用已排序數組、二進制搜索和32位固定長度的哈希表達。
隨機投影計算距離是使用近似餘弦距離。
n_estimators : int (default = 10)
樹的數量
min_hash_match : int (default = 4)
最小哈希搜索長度/個數。小於則中止
n_candidates : int (default = 10)
每一顆樹評估數量的最小值。反正至少每棵樹要評估幾回,雨露均沾
n_neighbors : int (default = 5)
檢索時。最小近鄰個數,就怕你忘記忘了設置檢索數量了
radius : float, optinal (default = 1.0)
檢索時。近鄰個體的距離半徑
radius_cutoff_ratio : float, optional (default = 0.9)
檢索時,半徑的下限,至關於相似性機率小於某閾值時,中止搜索,或者最小哈希搜索長度小於4也中止
random_state : int, RandomState instance or None, optional (default=None)
隨機數生成器使用種子。默認沒有
附帶屬性:
hash_functions_ : list of GaussianRandomProjectionHash objects
哈希函數g(p,x),每個樣本一個哈希化內容
trees_ : array, shape (n_estimators, n_samples)
Each tree (corresponding to a hash function) 每棵樹相應一個哈希散列。且這個哈希散列是通過排序的。顯示的是哈希值。n_estimators棵樹。n_samples個散列。
original_indices_ : array, shape (n_estimators, n_samples) 每棵樹相應一個哈希散列,哈希散列是通過排序的。顯示的是原數據序號index.
trees_ 和original_indices_ 就是兩種狀態,trees_ 是每棵通過排序樹的散列,original_indices_ 是每棵通過排序樹的序號Index.
.
Fit the LSH forest on the data.
數據加載投影樹
Get parameters for this estimator.
獲取樹裏面的相關參數
檢索函數,n_neighbors表明所需近鄰數。 不設置的話則返回初始化設置的數量。return_distance,是否打印/返回特定cos距離的樣本。
返回兩個array。一個是距離array。一個是機率array
Computes the (weighted) graph of k-Neighbors for points in X
數量檢索圖,n_neighbors表明所需近鄰數, 不設置的話則返回初始化設置的數量,mode=’connectivity’默認
加入數據到樹裏面,最好是批量導入。
Finds the neighbors within a given radius of a point or points.
半徑檢索。在給定的區間半徑內尋找近鄰,radius爲半徑長度。return_distance表明是否打印出內容。
Computes the (weighted) graph of Neighbors for points in X
半徑檢索圖
Set the parameters of this estimator.
重設部分參數
.
>>> from sklearn.neighbors import LSHForest
>>> X_train = [[5, 5, 2], [21, 5, 5], [1, 1, 1], [8, 9, 1], [6, 10, 2]]
>>> X_test = [[9, 1, 6], [3, 1, 10], [7, 10, 3]]
>>> lshf = LSHForest(random_state=42)
>>> lshf.fit(X_train)
LSHForest(min_hash_match=4, n_candidates=50, n_estimators=10,
n_neighbors=5, radius=1.0, radius_cutoff_ratio=0.9,
random_state=42)
>>> distances, indices = lshf.kneighbors(X_test, n_neighbors=2)
>>> distances
array([[ 0.069..., 0.149...],
[ 0.229..., 0.481...],
[ 0.004..., 0.014...]])
>>> indices
array([[1, 2],
[2, 0],
[4, 0]])
LSHForest(random_state=42)樹的初始化,
lshf.fit(X_train)開始把數據加載初始化的樹;
lshf.kneighbors(X_test, n_neighbors=2)。找出X_test每個元素的前2個(n_neighbors)相似內容。
當中。這個是cos距離,不是相似性,假設要直觀,可以被1減。
.
來源於:用docsim/doc2vec/LSH比較兩個文檔之間的相似度
# 使用lsh來處理
tfidf_vectorizer = TfidfVectorizer(min_df=3, max_features=None, ngram_range=(1, 2), use_idf=1, smooth_idf=1,sublinear_tf=1)
train_documents = []
for item_text in raw_documents:
item_str = util_words_cut.get_class_words_with_space(item_text)
train_documents.append(item_str)
x_train = tfidf_vectorizer.fit_transform(train_documents)
test_data_1 = '你好。我想問一下我想離婚他不想離,孩子他說不要,是六個月就本身主動生效離婚'
test_cut_raw_1 = util_words_cut.get_class_words_with_space(test_data_1)
x_test = tfidf_vectorizer.transform([test_cut_raw_1])
lshf = LSHForest(random_state=42)
lshf.fit(x_train.toarray())
distances, indices = lshf.kneighbors(x_test.toarray(), n_neighbors=3)
print(distances)
print(indices)
通常lsh比較適合作短文本的比較
.
相關屬性得到
# 屬性
lshf.trees_
# 每棵樹,排序散列的哈希值
lshf.hash_functions_
# 每棵樹的hash公式
lshf.original_indices_
# 每棵樹,排序散列的序號index
近期鄰檢索的圖:kneighbors_graph
lshf.kneighbors_graph(X_test, n_neighbors=5, mode='connectivity')
新增數據到樹裏面:
partial_fit(X_test)