介紹
大家好,博主又來給大家分享知識了。本來博主計劃完成稠密向量表示的內容分享后,就開啟自然語言處理中文本表示的講解。可在整理分享資料的時候,博主發現還有個知識點,必須得單獨拎出來好好說道說道。
這就是TF-IDF,也就是詞頻-逆文檔頻率。它在自然語言處理里堪稱“幕后功臣”,在文本表示、文本分類、信息檢索等諸多關鍵任務中,發揮著超乎想象的作用。那么,我們直接進入正題。
TF-IDF
在自然語言處理(NLP)領域,理解文本數據的含義并從中提取有價值的信息是核心任務。TF-IDF(Term Frequency-Inverse Document Frequency)作為一種重要的統計方法,在文本表示、文本分類、信息檢索、關鍵詞提取等眾多任務中發揮著關鍵作用。
基礎概念
詞頻
Term Frequency, TF。詞頻衡量的是一個詞在一篇文檔中出現的頻率。直觀地說,一個詞在文檔中出現的次數越多,它對該文檔的重要性可能越高。例如,在文檔“我喜歡蘋果,蘋果很美味”中,“蘋果”這個詞出現了兩次,相對其他詞出現的頻率較高,可能在該文檔中具有一定重要性。
其計算公式為:
其中,表示詞
在文檔
中的詞頻,
是詞
在文檔
中出現的次數,
是文檔
中所有詞的出現次數總和。
逆文檔頻率
Inverse Document Frequency, IDF。逆文檔頻率反映了一個詞在整個文檔集合中的普遍重要性。如果一個詞在大量文檔中都出現,那么它對于區分不同文檔的作用就較小。相反,一個只在少數文檔中出現的詞,對于識別這些特定文檔更為關鍵。
例如,“的”,“是”等常用詞在幾乎所有文檔中都會頻繁出現,它們的區分能力較弱。而專業術語如“量子糾纏”,只在特定領域的文檔中出現,其區分能力較強。
其計算公式為:
其中,表示詞
的逆文檔頻率,
是文檔集合中的文檔總數,
是包含詞
的文檔數量。
TF-IDF加權
TF-IDF加權綜合了詞頻和逆文檔頻率,通過將兩者相乘得到每個詞在文檔中的TF-IDF值。
公式為:
TF-IDF值越高,說明該詞對當前文檔越重要,同時在整個文檔集中相對不常見,具有較強的區分性。
代碼實現
計算詞頻(TF)
完整代碼
# 從collections模塊導入Counter類,用于統計元素出現的次數
from collections import Counter# 定義一個名為NLPTextRepresentation的類,用于處理文本表示相關任務
class NLPTextRepresentation:# 類的初始化方法,此處不做任何初始化操作def __init__(self):# pass 語句占位,不進行實際操作pass# 定義一個方法,用于計算文檔中每個單詞的詞頻(TF)def compute_tf(self, document):# 將輸入的文檔按空格分割成單詞列表words = document.split()# 使用Counter統計每個單詞在文檔中出現的次數word_count = Counter(words)# 計算文檔中單詞的總數total_words = len(words)# 初始化一個空字典,用于存儲每個單詞的詞頻tf_dict = {}# 遍歷統計結果中的每個單詞及其出現次數for word, count in word_count.items():# 計算該單詞的詞頻并存儲到字典中tf_dict[word] = count / total_words# 返回存儲詞頻的字典return tf_dict# 當腳本作為主程序運行時執行以下代碼
if __name__ == "__main__":# 創建NLPTextRepresentation類的一個實例nlp_text_representation = NLPTextRepresentation()# 定義一個示例文檔document = "我喜歡蘋果 蘋果很美味"# 調用compute_tf方法計算文檔中單詞的詞頻tf_result = nlp_text_representation.compute_tf(document)# 打印計算得到的詞頻結果print(tf_result)
運行結果
{'我喜歡蘋果': 0.5, '蘋果很美味': 0.5}進程已結束,退出代碼為 0
在這段代碼中,首先使用split()方法將輸入的文檔字符串分割成單詞列表。然后,利用Counter類統計每個單詞在文檔中出現的次數。
接著,計算文檔的總詞數,通過遍歷每個單詞及其出現次數,將每個單詞的出現次數除以總詞數,得到該單詞在文檔中的詞頻,并存儲在字典tf_dict中。
最后返回這個字典,其中鍵為單詞,值為對應的詞頻。
計算逆文檔頻率(IDF)
完整代碼
# 導入math模塊,用于使用數學函數,這里主要是為了計算對數
import math# 定義一個名為NLPTextRepresentation的類,用于處理自然語言處理中的文本表示相關任務
class NLPTextRepresentation:# 類的初始化方法,目前不做任何初始化操作def __init__(self):# 占位語句,不執行任何實際邏輯pass# 定義一個方法,用于計算語料庫中每個單詞的逆文檔頻率(IDF)def compute_idf(self, corpus):# 計算語料庫中文檔的總數total_docs = len(corpus)# 初始化一個空字典,用于存儲每個單詞在多少個文檔中出現過word_in_doc_count = {}# 遍歷語料庫中的每一個文檔for doc in corpus:# 將當前文檔按空格分割成單詞,并使用 set 去重words = set(doc.split())# 遍歷當前文檔中出現的每個唯一單詞for word in words:# 如果該單詞還未在word_in_doc_count字典中if word not in word_in_doc_count:# 則將該單詞添加到字典中,并將其出現文檔數初始化為 1word_in_doc_count[word] = 1else:# 否則,將該單詞出現的文檔數加 1word_in_doc_count[word] += 1# 初始化一個空字典,用于存儲每個單詞的逆文檔頻率idf_dict = {}# 遍歷word_in_doc_count字典中的每個單詞及其出現文檔數for word, count in word_in_doc_count.items():# 計算該單詞的逆文檔頻率(使用自然對數),并存儲到idf_dict中idf_dict[word] = math.log(total_docs / count)# 返回存儲逆文檔頻率的字典return idf_dict# 當腳本作為主程序運行時執行以下代碼
if __name__ == "__main__":# 創建NLPTextRepresentation類的一個實例nlp_text_representation = NLPTextRepresentation()# 定義一個語料庫,包含多個文檔corpus = ["我喜歡蘋果 蘋果很美味", "我喜歡香蕉 香蕉很甜", "蘋果和香蕉都是水果"]# 調用compute_idf方法計算語料庫中每個單詞的逆文檔頻率idf_result = nlp_text_representation.compute_idf(corpus)# 打印計算得到的逆文檔頻率結果print(idf_result)
運行結果
{'我喜歡蘋果': 1.0986122886681098, '蘋果很美味': 1.0986122886681098, '我喜歡香蕉': 1.0986122886681098, '香蕉很甜': 1.0986122886681098, '蘋果和香蕉都是水果': 1.0986122886681098}進程已結束,退出代碼為 0
在這段代碼中,首先計算語料庫中總的文檔數量。然后,遍歷語料庫中的每一篇文檔,將文檔中的單詞通過set()方法去重,以確保每個單詞只被統計一次。
對于每個單詞,如果它不在word_in_doc_count字典中,則將其初始值設為 1;如果已經存在,則將其對應的值加 1,這樣word_in_doc_count字典記錄了每個單詞在多少篇文檔中出現過。
接下來,通過遍歷word_in_doc_count字典,根據逆文檔頻率的計算公式,計算每個單詞的逆文檔頻率,并存儲在idf_dict字典中返回。
計算詞頻-逆文檔頻率(TF-IDF)
完整代碼
# 從collections模塊導入Counter類,用于統計元素出現的次數
from collections import Counter
# 導入math模塊,用于使用數學函數,這里主要是為了計算對數
import math# 定義一個名為NLPTextRepresentation的類,用于處理自然語言處理中的文本表示相關任務
class NLPTextRepresentation:# 類的初始化方法,目前不做任何初始化操作def __init__(self):# 占位語句,不執行任何實際邏輯pass# 定義一個方法,用于計算文檔中每個單詞的詞頻(TF)def compute_tf(self, document):# 將輸入的文檔按空格分割成單詞列表words = document.split()# 使用Counter統計每個單詞在文檔中出現的次數word_count = Counter(words)# 計算文檔中單詞的總數total_words = len(words)# 初始化一個空字典,用于存儲每個單詞的詞頻tf_dict = {}# 遍歷統計結果中的每個單詞及其出現次數for word, count in word_count.items():# 計算該單詞的詞頻并存儲到字典中tf_dict[word] = count / total_words# 返回存儲詞頻的字典return tf_dict# 定義一個方法,用于計算語料庫中每個單詞的逆文檔頻率(IDF)def compute_idf(self, corpus):# 計算語料庫中文檔的總數total_docs = len(corpus)# 初始化一個空字典,用于存儲每個單詞在多少個文檔中出現過word_in_doc_count = {}# 遍歷語料庫中的每一個文檔for doc in corpus:# 將當前文檔按空格分割成單詞,并使用set去重words = set(doc.split())# 遍歷當前文檔中出現的每個唯一單詞for word in words:# 如果該單詞還未在word_in_doc_count字典中if word not in word_in_doc_count:# 則將該單詞添加到字典中,并將其出現文檔數初始化為1word_in_doc_count[word] = 1else:# 否則,將該單詞出現的文檔數加1word_in_doc_count[word] += 1# 初始化一個空字典,用于存儲每個單詞的逆文檔頻率idf_dict = {}# 遍歷word_in_doc_count字典中的每個單詞及其出現文檔數for word, count in word_in_doc_count.items():# 計算該單詞的逆文檔頻率(使用自然對數),并存儲到idf_dict中idf_dict[word] = math.log(total_docs / count)# 返回存儲逆文檔頻率的字典return idf_dict# 定義一個方法,用于計算語料庫中每個文檔里單詞的TF-IDF值def compute_tfidf(self, corpus):# 初始化一個空列表,用于存儲每個文檔的TF-IDF結果tfidf_corpus = []# 調用compute_idf方法計算語料庫中所有單詞的逆文檔頻率idf = self.compute_idf(corpus)# 遍歷語料庫中的每一個文檔for doc in corpus:# 調用compute_tf方法計算當前文檔中每個單詞的詞頻tf = self.compute_tf(doc)# 初始化一個空字典,用于存儲當前文檔中每個單詞的TF-IDF值tfidf_doc = {}# 遍歷當前文檔詞頻字典中的每個單詞for word in tf:# 計算該單詞的TF-IDF值并存儲到字典中tfidf_doc[word] = tf[word] * idf[word]# 將當前文檔的TF-IDF結果添加到tfidf_corpus列表中tfidf_corpus.append(tfidf_doc)# 返回存儲所有文檔TF-IDF結果的列表return tfidf_corpus# 當腳本作為主程序運行時執行以下代碼
if __name__ == "__main__":# 創建NLPTextRepresentation類的一個實例nlp_text_representation = NLPTextRepresentation()# 定義一個包含多個文檔的語料庫corpus = ["我喜歡蘋果 蘋果很美味", "我喜歡香蕉 香蕉很甜", "蘋果和香蕉都是水果"]# 調用compute_tfidf方法計算語料庫中每個文檔里單詞的TF-IDF值tfidf_result = nlp_text_representation.compute_tfidf(corpus)# 遍歷計算得到的TF-IDF結果列表for i, doc in enumerate(tfidf_result):# 打印每個文檔的TF-IDF計算結果print(f"文檔{i + 1}的TF-IDF結果: {doc}")
運行結果
文檔1的TF-IDF結果: {'我喜歡蘋果': 0.5493061443340549, '蘋果很美味': 0.5493061443340549}
文檔2的TF-IDF結果: {'我喜歡香蕉': 0.5493061443340549, '香蕉很甜': 0.5493061443340549}
文檔3的TF-IDF結果: {'蘋果和香蕉都是水果': 1.0986122886681098}進程已結束,退出代碼為 0
這段代碼首先調用前面定義的compute_idf函數計算整個語料庫的逆文檔頻率。然后,遍歷語料庫中的每一篇文檔,對每篇文檔調用compute_tf函數計算詞頻。
接著,對于每個詞,將其在當前文檔中的詞頻乘以其在整個語料庫中的逆文檔頻率,得到該詞在當前文檔中的TF-IDF值,并存儲在tfidf_doc字典中。
最后,將每篇文檔的TF-IDF字典結果添加到tfidf_corpus列表中并返回。這段代碼的目的是將前面計算得到的詞頻和逆文檔頻率進行綜合計算,得到每篇文檔中每個詞的TF-IDF值,從而完成TF-IDF加權的計算過程。?
TF-IDF的優點
- 簡單有效:TF-IDF的計算原理直觀易懂,實現相對簡單,不需要復雜的模型訓練過程,卻能在很多實際應用中取得較好的效果,如文本分類、信息檢索等。
- 突出關鍵信息:通過加權計算,能夠突出那些在特定文檔中頻繁出現且在整個文檔集中相對不常見的詞,這些詞往往與文檔的主題緊密相關,有助于快速定位文檔的核心內容。
- 可擴展性好:無論是小規模還是大規模的文檔集合,TF-IDF都能適用,并且計算資源消耗相對可控。在處理大規模文本數據時,可以通過分布式計算等方式進一步優化計算效率。
TF-IDF的缺點
- 忽略語義信息:TF-IDF只考慮了詞的出現頻率和文檔分布,完全沒有涉及詞與詞之間的語義關系。例如,“汽車”和“轎車”在語義上相近,但TF-IDF無法體現這種關系,可能會導致在一些需要語義理解的任務中效果不佳。
- 依賴文檔集合:逆文檔頻率的計算依賴于整個文檔集合,當文檔集合發生變化時,需要重新計算IDF值,這在實時性要求較高的應用場景中可能會帶來不便。
- 無法處理多義詞:對于具有多種含義的詞,TF-IDF不能區分其在不同上下文中的語義差異,會將其視為同一個詞進行計算,可能影響對文本的準確理解。
結論賦能
TF-IDF作為自然語言處理中的經典方法,在文本分析的眾多領域有著廣泛應用。通過對詞頻和逆文檔頻率的巧妙結合,能夠有效地提取文本中的關鍵信息,為后續的文本處理任務提供有力支持。
然而,其固有的局限性也為研究人員提供了改進和創新的方向。在實際應用中,需要根據具體任務的需求和數據特點,合理選擇是否使用TF-IDF,并結合其他技術(如詞向量模型等)來彌補其不足,以更好地實現自然語言處理的目標。
結束
好了,以上就是本次分享的全部內容了。不知道大家是否對TF-IDF有了更深入的理解,以及對其在實際應用中的潛力有了新的認識呢?希望本次分享能為大家在自然語言處理的學習和實踐中帶來啟發和幫助。
隨著自然語言處理技術的不斷發展,我們期待看到更多能夠克服TF-IDF局限性的創新方法涌現。無論是在文本分類、信息檢索,還是在文本摘要等領域,TF-IDF都已經奠定了堅實的基礎,激勵著研究者們不斷探索更高效、更精準的文本處理策略。
那么本次分享就到這里了。最后,博主還是那句話:請大家多去大膽的嘗試和使用,成功總是在不斷的失敗中試驗出來的,敢于嘗試就已經成功了一半。如果大家對博主分享的內容感興趣或有幫助,請點贊和關注。大家的點贊和關注是博主持續分享的動力🤭,博主也希望讓更多的人學習到新的知識。