2017-08-29 136 views
0

我試圖來計算語料庫文本文檔的所有可能的組合之間的餘弦相似度得分。我正在使用scikit-learn的cosine_similarity函數來執行此操作。由於我的語料庫非常龐大(3000萬份文檔),因此語料庫中文檔之間的可能組合數量太多,無法存儲爲數據框。因此,在將它們存儲在數據框中供將來使用之前,我想使用閾值過濾相似性分數,因爲它們正在創建。雖然我這樣做了,但我也希望將這些文檔中的每個文檔的相應ID分配給數據框的索引和列名稱。因此,對於數據框中的數據值,每個值應具有索引(行)和列名稱,這些文檔ID是值爲餘弦相似性分值的文檔ID。過濾餘弦相似度得分爲大熊貓數據幀

similarity_values = pd.DataFrame(cosine_similarity(tfidf_matrix), index = IDs, columns= IDs) 

這段代碼運行良好,沒有過濾部分。 IDs是一個列表變量,它具有與tfidf矩陣相對應的所有文檔ID。

similarity_values = pd.DataFrame(cosine_similarity(tfidf_matrix)>0.65, index = IDs, columns= IDs) 

此修改有助於篩選,但相似性分數轉換爲布爾(真/假)值。我怎樣才能保持實際的餘弦相似度分數而不是布爾真/假值。

+0

cosine_similarity將輸出一個方陣並且它可能的是在單個列中的一個值是> 0.65和其它的是以下。那麼在那種情況下,您希望該列出現在數據框中? –

+0

@VivekKumar好問題。我希望數據框的所有值都堆疊在一起。即數據幀中的每一行應該只有一個相似度分數和相應的文檔ID。 'similar_values = similarity_values.stack()。reset_index()。rename(columns = {'level_0':'ID1','level_1':'ID2',0:'Score'})' – Minu

回答

0

3E7 x 3E7是荒謬矩陣大小。在低性能筆記本電腦/臺式機上實現這一目標的唯一方法是使用生成器來減少內存佔用,並將問題細分爲效率問題。

以下函數使用的發電機廠,並使用雙for遍歷組塊的笛卡爾乘積。我們預先計算語料庫中每個tfidf的規範。

這不是設計爲較小的數據這樣做同樣的任務最快的解決方案。這是爲了在一臺適度的機器的內存中完成這項任務。

from scipy.sparse import coo_matrix 
import numpy as np 

def f(t, c, p=-1, v=False): 
    n = (t ** 2).sum(1) ** .5 
    g = lambda: ((x, t[x:x+c]) for x in range(0, t.shape[0], c)) 
    h = lambda a, b, i, j: a.dot(b.T)/n[i:i+c, None]/n[j:j+c] 
    d = lambda s: (s * (1 - np.eye(s.shape[0]))) 

    for i, a in g(): 
     for j, b in g(): 
      s = h(a, b, i, j) 
      if i == j: 
       s = d(s) 
      i_, j_ = np.where(s > p) 
      if v: 
       print('\r', 'i = {:0000000d}; j = {:0000000d}'.format(i, j), end='') 
      yield s[i_, j_], i_ + i, j_ + j 

有了,我們通過計算它們自己在每個分塊和跟蹤的相似之處比我們的閾值提取餘弦相似。

最後,我們通過足夠的相似用的相似的座標以一個稀疏矩陣構造,並將結果指定到名稱m。如果您需要矩陣表示,請使用m.toarray()

values, *ij = zip(*f(tfidf_matrix, 5000, .8, v=True)) 

values = np.concatenate(values) 
ij = list(map(np.concatenate, ij)) 

m = coo_matrix((values, ij)) 

請注意,我零對角線。否則,如果我們使用閾值-1,這將產生與sklearn.metrics.pairwise中的cosine_similarity完全相同的內容。

相同的煩躁的驗證

from sklearn.metrics.pairwise import cosine_similarity 

tfidf_matrix = np.random.randint(10, size=(1000, 100)) 
s = cosine_similarity(tfidf_matrix) 

values, *ij = zip(*f(tfidf_matrix, 5000, -1, v=True)) 

values = np.concatenate(values) 
ij = list(map(np.concatenate, ij)) 

m = coo_matrix((values, ij)) 

# This should be equal the 1000. The number of 1's in the diagonal. 
(s - m.toarray()).sum() 

1000.0 
+0

請詳細解釋一下你的功能正在做什麼,每個變量的含義是什麼? – Minu

+0

對不起,不。這需要很長時間才能完成。我根本沒有時間去詳細解釋一切。你會注意到沒有人花時間。那是因爲它是一筆巨大的時間投資。我會爲您提供這一點,我將矩陣細分爲區塊,只保存超過閾值的位置和值。除此之外,將其作爲一項任務來了解代碼的每個部分的功能。此外,它可能會幫助您理解我們自願回答問題的時間。我們不想浪費時間。你應該儘量不要這樣做。 – piRSquared