一、基本定義及公式
TF-IDF用來評估一個字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。字詞的重要性隨着它在文件中出現的次數成正比增加,但同時會隨着它在語料庫中出現的頻率反比下降。如果某個單詞在一篇文章中出現的頻率TF高,並且在其他文章中很少出現(即代表它有明顯的區分度),則認爲此詞或者短語具有很好的類別區分能力,適合分類
一些基礎概念:文章畫像是描述每篇文章以給定一些詞。主要是由主題詞與關鍵詞組成,兩者最大的區別就是主題詞經過了規範化處理。
關鍵詞:文章中一些詞權重高的詞語。主題詞:是進行了規範化處理,文章中出現同義詞,計算結果出現次數高的詞。
TF(term frequency)詞頻:表示關鍵詞在文本中出現的頻率(通常會被歸一化,以防止其對長文件的偏向),它並不能作爲文本相似度的衡量標準,因爲如若在給定的一篇中文文檔中出現的頻率非常高的話,但這些詞在每篇文章中都具有非常高的詞頻(在語料庫中反覆出現),那麼會使得其在每篇文章中都會被命中。
表示關鍵詞在文件中出現的次數,分母則代表中所有詞彙出現的次數。
IDF(inverse document frequency)逆文檔頻率:對某一特定詞語的IDF,可以由總文件數目除以包含該詞語的文件數,再將得到的商取對數即可得到。
其中是語料庫中所有文檔總數,分母是包含詞語的所有文檔數。
TF-IDF以TF和IDF的乘積作爲取值測度,並用它完成對權值TF的調整,調整的目的在於突出重要單詞,抑制次要單詞。其單純地認爲文本頻率小的單詞越重要,文本頻率大的單詞就越無用,顯然這並不是完全正確的。
二、計算方法
關鍵詞與主題詞的計算方法:
關鍵詞:TEXTRANK計算出的結果TOP-K個詞及權重
主題詞:TEXTRANK的TOP-K詞語TF-IDF計算的TOP-K個詞的交集
利用TF-IDF從文章中抽取相應的畫像
步驟:
①讀取N篇文章數據,然後對文章數據進行分詞處理
②使用Spark.ml(Spark MLlib)的count與IDF進行計算,先計算分詞之後每篇文章的詞頻,然後根據詞頻計算IDF以及詞,得到IDF模型
利用②得到的模型計算N篇文章數據的TF-IDF值。
三、Python部分代碼
def segmentation(partition):
import os
import re
import jieba
import jieba.analyse
import jieba.posseg as pseg
import codecs
abspath = '/home/admin01/project/words'
# jieba加載用戶詞典
userDict_path = os.path.join(abspath, 'ITKeywords.txt')
jieba.load_userdictad(userDict_path)
# 停用詞文本
stopwords_path = os.path.join(abspath, 'stopwords.txt')
def get_stopwords_list():
"""
返回stopwords列表
"""
stopwords_list = [i.strip() for i in codecs.open(stopwords_path).readlines()]
return stopwords_list
# 獲得所有的停用詞列表
stopwords_list = get_stopwords_list()
# 分詞
def cur_sentenct(sentence):
"""
對切割之後的詞語進行過濾,去掉停用詞,保留名詞,英文和自定義詞庫中的詞,長度大於2的詞
"""
seg_list = pseg.lcut(sentence)
seg_list = [i for i in seg_list if i.flag not in stopwords_list]
filterd_words_list = []
for seg in seg_list:
if len(seg.word) <= 1:
continue
elif seg.flag == 'eng':
if len(seg.word) <= 2:
continue
else:
filtered_words_list.append(seg.word)
elif seg.flag.startswith('n'):
filtered_words_list.append(seg.word)
elif seg.flag in ['x', 'eng']:
filtered_words_list.append(seg.word)
return filtered_words_list
for row in partition:
sentence = re.sub('<.*?>', '', row_sentence) #替換標籤數據
words = cut_sentence(sentence)
yield row.article_id, row.channel_id, words
# 詞語和詞頻統計
from pyspark.ml.feature import CountVectorizer
# 總詞彙的大小,文本中必須出現的次數
cv = CountVectorizer(inputCol = 'words', outputCol = 'countFeatures', vocabSize = 200
* 10000, minDF = 1.0)
# 訓練詞頻統計模型
cv_model = cv.fit(words_df)
cv_model.write().overwrite().save('hdfs://Linux02:8020/headlines/models/CV.model')
# 詞語與詞頻統計
from pyspark.ml.feature import CountVectorizerModel
cv_model = CountVectorizerModel.load('hdfs://LInux02:8020/headlines/model/CV.model')
# 得到詞頻向量結果
cv_result = cv_model.transform(words_df)
# 訓練IDF模型
from pyspark.ml.feature import IDF
idf = IDF(inputCol = 'countFeatures', outputCol = 'idfsFeatures')
idf_model = idf.fit(cv_result)
idf_model.write().overwrite().save('hdfs://Linux02:8020/headlines/models/IDF.model')
from pyspark.ml.feature import CountVectorizerModel
cv_model = CountVectorizerModel.load('hdfs://Linux02:8020/headlines/models/countVectorizerOfArticleWords.model')
from pyspark.ml.feature import IDFModel
idf_model = IDFModel.load('hdfs://Linux02:8020//headlines/models/IDFOfArticleWords.model')
keywords_list_with_idf = list(zip(cv_model.vocabulay, idf_model.toArray()))
def append_index(data):
for index in range(len(data)):
data[index] = list(data[index]) # 將元組轉化爲list
data[index].append(index) # 加入索引
data[index][1] = float(data[index][1])
append_index(keywords_list_with_idf)
sc = spark.sparkContext()
rdd = sc.parallelize(keywords_list_with_idft) # 創建RDD
idf_keywords = rdd.toDF(['keywords', 'idf', 'index'])
idf_keywords.write.insertInto('idf_keywords_values')