計算文檔的TF-IDF值
參考鏈接:
英文文本挖掘預處理流程總結,文本挖掘預處理之向量化,文本挖掘預處理之TF-IDF
1.TF-IDF
TF-IDF(Term Frequency-Inverse Document Frequency, 詞頻-逆文件頻率)。
是一種用於資訊檢索與資訊探勘的常用加權技術。TF-IDF是一種統計方法,用以評估一字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。字詞的重要性隨着它在文件中出現的次數成正比增加,但同時會隨着它在語料庫中出現的頻率成反比下降.
上述引用總結就是, 一個詞語在一篇文章中出現次數越多, 同時在所有文檔中出現次數越少, 越能夠代表該文章.
詞頻 (term frequency, TF) 指的是某一個給定的詞語在該文件中出現的次數。這個數字通常會被歸一化(一般是詞頻除以文章總詞數), 以防止它偏向長的文件。(同一個詞語在長文件里可能會比短文件有更高的詞頻,而不管該詞語重要與否.)
但是, 需要注意, 一些通用的詞語對於主題並沒有太大的作用, 反倒是一些出現頻率較少的詞才能夠表達文章的主題, 所以單純使用是TF不合適的。權重的設計必須滿足:一個詞預測主題的能力越強,權重越大,反之,權重越小。所有統計的文章中,一些詞只是在其中很少幾篇文章中出現,那么這樣的詞對文章的主題的作用很大,這些詞的權重應該設計的較大。IDF就是在完成這樣的工作.
詞頻的計算公式:
逆向文件頻率 (inverse document frequency, IDF) IDF的主要思想是:如果包含詞條t的文檔越少, IDF越大,則說明詞條具有很好的類別區分能力。某一特定詞語的IDF,可以由總文件數目除以包含該詞語之文件的數目,再將得到的商取對數得到。
公式:
其中,分子是語料庫中的文件總數,分母是包含詞語的文件數目(即目的文件數目)。如果該詞語不在語料庫中,就會導致分母為零,因此一般情況下分母要+1,即:
某一特定文件內的高詞語頻率,以及該詞語在整個文件集合中的低文件頻率,可以產生出高權重的TF-IDF。因此,TF-IDF傾向於過濾掉常見的詞語,保留重要的詞語。
公式:
2.文本預處理
為了計算文本的TF-IDF值,我們需要將待處理的文本轉化成比較好處理的形式。
a.除去非文本部分
在一篇文章中,總會有很多的空格和標點符號,比如;,"等等,這里我們處理的方式非常簡單,只需要使用正則表達式的sub函數,將非文本部分代替為空格即可。
def Filter_text(text):
str = re.sub('[^a-zA-Z]', ' ', text)
return re.sub(r'\s+', ' ', str)
除此之外,還需要大小寫轉換
def Lower_text(text):
return text.lower()
b.詞形還原
我們利用詞形還原的方法,將文本中的詞轉化為相同的形式,這樣才能更好地計算TF值。比如,country和countries其實是表達的相同的意思,但是如果不做詞形還原,他們的TF值就會分別被計算。在實際應用中,一般使用nltk的WordNetLemmatizer類來進行詞型還原。詞形還原代碼如下
# 使用WordNetLemmatizer類,即wordnet詞形還原方法
def Lemmatization_text(text_cut_list):
wnl = WordNetLemmatizer()
return [wnl.lemmatize(n) for n in text_cut_list]
這里,由於詞形還原是以一個list為單位進行的,因此在之前我們要進行一個轉化
# 將article中的文章轉化成由單詞構成的list
def text_cut(text):
return re.findall('[a-zA-z]+', text)
在有些程序里,我們也使用詞干提取來進行類似的操作。事實上,詞干提取(stemming)和詞型還原(lemmatization)是英文文本預處理的特色。兩者其實有共同點,即都是要找到詞的原始形式。只不過詞干提取(stemming)會更加激進一點,它在尋找詞干的時候可以會得到不是詞的詞干。比如"imaging"的詞干可能得到的是"imag", 並不是一個詞。而詞形還原則保守一些,它一般只對能夠還原成一個正確的詞的詞進行處理。詞干提取還有PorterStemmer,LancasterStemmer和SnowballStemmer等方法,這里我沒有用到,因此不做說明。
c.停用詞處理
一篇文章中有很多無效的詞,比如“a”,“to”,一些短詞,還有一些標點符號,這些我們不想在文本分析的時候引入,因此需要去掉,這些詞就是停用詞。在我們用scikit-learn做特征處理的時候,可以通過參數stop_words來引入一個數組作為停用詞表。
# 過濾停用詞以及長度小於3的詞
def Stopwords_text(text_cut_list):
Stop_Word_list = stopwords.words("english")
return [n for n in text_cut_list if n not in Stop_Word_list and len(n) >= 3]
計算TF-IDF的值
在scikit-learn中,有兩種方法進行TF-IDF的預處理。第一種方法是在用CountVectorizer類向量化之后再調用TfidfTransformer類進行預處理。第二種方法是直接用TfidfVectorizer完成向量化與TF-IDF預處理。
用CountVectorizer類向量化其實是一種統計詞頻的方法,第一種方法的過程就是,先統計詞頻,再計算TF-IDF。代碼很簡單,如下:
def TF_IDF_count(text):
vectorizer = CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(text))
word = vectorizer.get_feature_names() # 所有文本的關鍵字
weight = tfidf.toarray() # 對應的tfidf矩陣
return [(word[j], float(weight[0][j])) for j in range(len(word))]
用第二種方法的話,就是用TfidfVectorizer一步到位,類似的代碼如下:
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf2 = TfidfVectorizer()
re = tfidf2.fit_transform(corpus)
代碼
最后的代碼如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
# 導入文章到list
def Insert_text():
L = []
with open('E:/pypy/TF-IDF/101666.txt', 'r') as f:
L.append(f.read())
return L
# 將text中的標點符號和數字過濾
# 第二次過濾合並多個空格
def Filter_text(text):
str = re.sub('[^a-zA-Z]', ' ', text)
return re.sub(r'\s+', ' ', str)
# 將大寫轉化為小寫
def Lower_text(text):
return text.lower()
# 使用WordNetLemmatizer類,即wordnet詞形還原方法
def Lemmatization_text(text_cut_list):
wnl = WordNetLemmatizer()
return [wnl.lemmatize(n) for n in text_cut_list]
# 將article中的文章轉化成由單詞構成的list
def text_cut(text):
return re.findall('[a-zA-z]+', text)
# 過濾停用詞以及長度小於3的詞
def Stopwords_text(text_cut_list):
Stop_Word_list = stopwords.words("english")
return [n for n in text_cut_list if n not in Stop_Word_list and len(n) >= 3]
# 計算TF-IDF
def TF_IDF_count(text):
vectorizer = CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(text))
word = vectorizer.get_feature_names() # 所有文本的關鍵字
weight = tfidf.toarray() # 對應的tfidf矩陣
return [(word[j], float(weight[0][j])) for j in range(len(word))]
def main():
article = Insert_text()
article[0] = Filter_text(article[0])
article[0] = Lower_text(article[0])
word_cut = Lemmatization_text(text_cut(article[0]))
word_cut = Stopwords_text(word_cut)
# print(Stopwords_text(word_cut))
article[0] = ''
for w in word_cut:
article[0] = article[0] + w + ' '
L = TF_IDF_count(article)
print(sorted(L, key=lambda x: (x[1]), reverse=True))
if __name__== "__main__":
print('test')
main()