TD-IDF

什麼是 TF-IDF 算法?

簡單來說,向量空間模型就是希望把查詢關鍵字和文檔都表達成向量,然後利用向量之間的運算來進一步表達向量間的關係。比如,一個比較常用的運算就是計算查詢關鍵字所對應的向量和文檔所對應的向量之間的 “相關度”。

在這裏插入圖片描述

TF (Term Frequency)—— “單詞頻率”

意思就是說,我們計算一個查詢關鍵字中某一個單詞在目標文檔中出現的次數。舉例說來,如果我們要查詢 “Car Insurance”,那麼對於每一個文檔,我們都計算“Car” 這個單詞在其中出現了多少次,“Insurance”這個單詞在其中出現了多少次。這個就是 TF 的計算方法。

TF 背後的隱含的假設是,查詢關鍵字中的單詞應該相對於其他單詞更加重要,而文檔的重要程度,也就是相關度,與單詞在文檔中出現的次數成正比。比如,“Car” 這個單詞在文檔 A 裏出現了 5 次,而在文檔 B 裏出現了 20 次,那麼 TF 計算就認爲文檔 B 可能更相關。

然而,信息檢索工作者很快就發現,僅有 TF 不能比較完整地描述文檔的相關度。因爲語言的因素,有一些單詞可能會比較自然地在很多文檔中反覆出現,比如英語中的 “The”、“An”、“But” 等等。這些詞大多起到了鏈接語句的作用,是保持語言連貫不可或缺的部分。然而,如果我們要搜索 “How to Build A Car” 這個關鍵詞,其中的 “How”、“To” 以及 “A” 都極可能在絕大多數的文檔中出現,這個時候 TF 就無法幫助我們區分文檔的相關度了。

IDF(Inverse Document Frequency)—— “逆文檔頻率”

就在這樣的情況下應運而生。這裏面的思路其實很簡單,那就是我們需要去 “懲罰”(Penalize)那些出現在太多文檔中的單詞。

也就是說,真正攜帶 “相關” 信息的單詞僅僅出現在相對比較少,有時候可能是極少數的文檔裏。這個信息,很容易用 “文檔頻率” 來計算,也就是,有多少文檔涵蓋了這個單詞。很明顯,如果有太多文檔都涵蓋了某個單詞,這個單詞也就越不重要,或者說是這個單詞就越沒有信息量。因此,我們需要對 TF 的值進行修正,而 IDF 的想法是用 DF 的倒數來進行修正。倒數的應用正好表達了這樣的思想,DF 值越大越不重要。

TF-IDF 算法主要適用於英文,中文首先要分詞,分詞後要解決多詞一義,以及一詞多義問題,這兩個問題通過簡單的tf-idf方法不能很好的解決。於是就有了後來的詞嵌入方法,用向量來表徵一個詞。

TF-IDF實際上是:TF * IDF

​ 某一特定文件內的高詞語頻率,以及該詞語在整個文件集合中的低文件頻率,可以產生出高權重的TF-IDF。因此,TF-IDF傾向於過濾掉常見的詞語,保留重要的詞語。

TF-IDF計算方式

在這裏插入圖片描述
在這裏插入圖片描述

TF-IDF 的4個變種

在這裏插入圖片描述
TF-IDF常見的4個變種

變種1:通過對數函數避免 TF 線性增長

很多人注意到 TF 的值在原始的定義中沒有任何上限。雖然我們一般認爲一個文檔包含查詢關鍵詞多次相對來說表達了某種相關度,但這樣的關係很難說是線性的。拿我們剛纔舉過的關於 “Car Insurance” 的例子來說,文檔 A 可能包含 “Car” 這個詞 100 次,而文檔 B 可能包含 200 次,是不是說文檔 B 的相關度就是文檔 A 的 2 倍呢?其實,很多人意識到,超過了某個閾值之後,這個 TF 也就沒那麼有區分度了。

用 Log,也就是對數函數,對 TF 進行變換,就是一個不讓 TF 線性增長的技巧。具體來說,人們常常用 1+Log(TF) 這個值來代替原來的 TF 取值。在這樣新的計算下,假設 “Car” 出現一次,新的值是 1,出現 100 次,新的值是 5.6,而出現 200 次,新的值是 6.3。很明顯,這樣的計算保持了一個平衡,既有區分度,但也不至於完全線性增長。

變種2:標準化解決長文檔、短文檔問題

經典的計算並沒有考慮 “長文檔” 和“短文檔”的區別。一個文檔 A 有 3,000 個單詞,一個文檔 B 有 250 個單詞,很明顯,即便 “Car” 在這兩個文檔中都同樣出現過 20 次,也不能說這兩個文檔都同等相關。對 TF 進行 “標準化”(Normalization),特別是根據文檔的最大 TF 值進行的標準化,成了另外一個比較常用的技巧

變種3:對數函數處理 IDF

第三個常用的技巧,也是利用了對數函數進行變換的,是對 IDF 進行處理。相對於直接使用 IDF 來作爲 “懲罰因素”,我們可以使用 N+1 然後除以 DF 作爲一個新的 DF 的倒數,並且再在這個基礎上通過一個對數變化。這裏的 N 是所有文檔的總數。這樣做的好處就是,第一,使用了文檔總數來做標準化,很類似上面提到的標準化的思路;第二,利用對數來達到非線性增長的目的。

變種4:查詢詞及文檔向量標準化

還有一個重要的 TF-IDF 變種,則是對查詢關鍵字向量,以及文檔向量進行標準化,使得這些向量能夠不受向量裏有效元素多少的影響,也就是不同的文檔可能有不同的長度。在線性代數裏,可以把向量都標準化爲一個單位向量的長度。這個時候再進行點積運算,就相當於在原來的向量上進行餘弦相似度的運算。所以,另外一個角度利用這個規則就是直接在多數時候進行餘弦相似度運算,以代替點積運算。

基於gensim TFIDF模型的文章推薦算法

https://tedboy.github.io/nlps/generated/generated/gensim.similarities.SparseMatrixSimilarity.html#gensim.similarities.SparseMatrixSimilarity
https://blog.csdn.net/ld326/article/details/78441773
https://blog.csdn.net/qq_34333481/article/details/85014010
一 訓練階段 輸入數據格式:一個列表,列表中的每個元素(也是列表)代表一個文本。每個文本分詞後的詞語組成的一個列表代表該文本。 生成的模型、tfidf矩陣、文章item_id列表,字典,語料分別保存。

gensim的TFIDF模型使用步驟

gensim版本的TFIDF模型的創建分爲一下5步:

  1. 將待對比文本集合預處理成[[vec1],[vec2]] ,一個列表,列表中的每個元素[vec1] (也是列表)代表一個文本。每個文本分詞後的詞語組成的一個列表代表該文本。這裏可以使用jieba分詞來進行文本得的分詞。

  2. 生成字典 dictionary = corpora.Dictionary(train)
    Dictionary encapsulates the mapping between normalized words and their integer ids.
    字典封裝了規範化單詞及其整數ID之間的映射。

  3. 生成語料 corpus = [dictionary.doc2bow(text) for text in train]
    Convert document into the bag-of-words (BoW) format = list of (token_id, token_count) tuples.
    將每一個文本轉化爲[(單詞所在字典位置,單詞數量)]

  4. 定義TFIDF模型 tfidf_model = models.TfidfModel(corpus, dictionary=dictionary)
    Objects of this class realize the transformation between word-document co-occurrence matrix (int) into a locally/globally weighted TF-IDF matrix (positive floats).

  5. 用語料訓練模型並生成TFIDF矩陣 corpus_tfidf = tfidf_model[corpus]
    詳細計算方式見上TF-IDF計算方式

  6. 生成餘弦相似度索引 index = similarities.SparseMatrixSimilarity(corpus_tfidf, num_features=featurenum) 使用SparseMatrixSimilarity(),可以佔用更少的內存和磁盤空間。
    Compute cosine similarity against a corpus of documents by storing the index matrix in memory.

  7. 測試階段,模型對測試集進行operation;求餘弦相似度。對於給定的新文本,找到訓練集中最相似的五篇文章作爲推薦。

餘弦相似度索引的三種計算方法

1 Similarity、MatrixSimilarity和SparseMatrixSimilarity
Similarity 、MatrixSimilarity、SparseMatrixSimilarity 都是 gensim.similarities.docsim 下的類。其對象爲相似索引index,都使用cosine相似度算法。

區別:
Similarity將索引緩存於硬盤(文件形式),MatrixSimilarity/SparseMatrixSimilarity 將索引數據置於內存。
Similarity支持迭代形式的數據輸入,MatrixSimilarity/SparseMatrixSimilarity要求輸入矩陣完全存在於內存中。
Similarity/SparseMatrixSimilarity生成的index計算最多利用單核,MatrixSimilarity則使用全部核心,cpu利用率基本爲100%。
SparseMatrixSimilarity相較於MatrixSimilarity,專門用於接收稀疏向量輸入。
(當輸入確實爲稀疏表示時,應優先使用SparseMatrixSimilarity,運算效率更高,內存消耗更小)
如何選擇
當輸入數據量較爲有限時,使用MatrixSimilarity/SparseMatrixSimilarity;數據量很大不能全部儲存在內存時,使用Similarity。
當輸入數據量較爲有限,且輸入爲稀疏表示時,使用SparseMatrixSimilarity。爲稠密表示則使用MatrixSimilarity。

代碼說明

1 import warnings   warnings.filterwarnings(action='ignore',category=UserWarning,module='gensim') 爲了不報警告。
2 pickle.dump() 報錯,需要有wirite屬性。改爲 from sklearn.externals import joblib。其dump 和load 方式和pickle一致。
3 index.get_similarities(test_vec) 返回test_vec 和訓練語料中所有文本的餘弦相似度。返回結果是個numpy數組 
4 related_doc_indices = sim.argsort()[:-6:-1] 完成對numpy數組的排序並獲取其top5最大值。
mport jieba
from gensim import corpora, models, similarities
# gensim的模型model模塊,可以對corpus進行進一步的處理,比如tf-idf模型,lsi模型,lda模型等
f = open('nbs_2017_data_35.txt','r',encoding='utf-8')
wordstest_model = f.read()
# wordstest_model = ["我去玉龍雪山並且喜歡玉龍雪山玉龍雪山","我在玉龍雪山並且喜歡玉龍雪山","我喜歡九寨溝","我在九寨溝,不知道你說啥",'我在九寨溝,很喜歡']
test_model = [[word for word in jieba.cut(words)] for words in wordstest_model]
dictionary = corpora.Dictionary(test_model,prune_at=2000000)
# for key in dictionary.iterkeys():
#     print key,dictionary.get(key),dictionary.dfs[key]
corpus_model= [dictionary.doc2bow(test) for test in test_model]
print(corpus_model)
# [[(0, 1), (1, 3), (2, 1), (3, 1), (4, 1)], [(0, 1), (1, 2), (3, 1), (4, 1), (5, 1)], [(0, 1), (5, 1), (6, 1)]]

# 目前只是生成了一個模型,並不是將對應的corpus轉化後的結果,裏面存儲有各個單詞的詞頻,文頻等信息
tfidf_model = models.TfidfModel(corpus_model)
# 對語料生成tfidf
corpus_tfidf = tfidf_model[corpus_model]


#使用測試文本來測試模型,提取關鍵詞,test_bow提供當前文本詞頻,tfidf_model提供idf計算
testword = "福建省仙遊縣蓋尾鎮石馬村"
test_bow = dictionary.doc2bow([word for word in jieba.cut(testword)])
# print(test_bow)
test_tfidf = tfidf_model[test_bow]


# 計算相似度
index = similarities.MatrixSimilarity(corpus_tfidf) #把所有評論做成索引
sims = index[test_tfidf]  #利用索引計算每一條評論和商品描述之間的相似度
maxs_index = sims.index(max(sims))
print(wordstest_model[maxs_index])

模型保存和加載

def tfidf_modle_save(dictionary, corpus_model, tfidf_model, corpus_tfidf):
    # model save
    dictionary.save(model_path + 'train_dictionary.dict')  # 保存生成的詞典
    tfidf_model.save(model_path + 'train_tfidf.model')
    corpora.MmCorpus.serialize(model_path + 'train_corpuse.mm', corpus_model)
    featurenum = len(dictionary.token2id.keys())  # 通過token2id得到特徵數
    # 稀疏矩陣相似度,從而建立索引,我們用待檢索的文檔向量初始化一個相似度計算的對象
    index = similarities.SparseMatrixSimilarity(corpus_tfidf, num_features=featurenum)
    index.save(model_path + 'train_index.index')
    
    

def tfidf_model_load():
    # model load
    dictionary = corpora.Dictionary.load(model_path + "train_dictionary.dict")
    tfidf_model = models.TfidfModel.load(model_path + "train_tfidf.model")
    index = similarities.SparseMatrixSimilarity.load(model_path + 'train_index.index')
    corpus_model = corpora.MmCorpus(model_path + 'train_corpuse.mm')
    print('模型加載完成')
    return dictionary, tfidf_model, index, corpus_model

參考文獻

https://easyai.tech/ai-definition/tf-idf/

https://blog.csdn.net/asialee_bird/article/details/81486700#2%E3%80%81TF-IDF%E5%BA%94%E7%94%A8

https://blog.csdn.net/qq_34333481/article/details/85327090

https://blog.csdn.net/hao5335156/article/details/87835851

https://www.jianshu.com/p/6e07729c6c5b

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章