TF就是词频,即一个词在文档中出现的次数。若同一个词在两个文档中出现频率都很高时,一般会认为该词与两个文档有很强的相关性,可以提取该词作为两个文档的关键词,两个文档也具有较高的相似度。
使用词频作为文档关键字的提取或相似度分析方法,会存在一个高频词的问题。虽然在分词阶段过滤掉了语气助词、副词、介词、连词等一些无意义的词,但一些在文档中有意义的高频词不能过滤,如喜欢、朋友、很多、工作、时间等等,这些高频词在不同文档中词频会很高,但与文档内容的相关性并不强,不能作为文档的关键词,更不能作为判断两个文档相似度的依据。
相对高频词来说,在文档中出现的一些不常用的低频词若词频比较高,那么它很可能与文档内容的相关性很强,让这些词作为文档的关键词和判断文档相似度的依据,效果会比较理想。例如篮球、当归等低频词,若篮球在一篇文档中出现频率很高,这篇文档很大几率与篮球有关,可以把篮球作为该篇文档的一个关键词,若篮球在两篇文档中出现词频都很高,说明这两篇文档都与篮球相关,有较高的内容相似度。
在这种情况下,需要强调这个低频词的重要性。在词频的基础上,再对每个词分配一个权重系数,若某个词比较少见,但是它在这篇文章中多次出现,就增加该词的权重系数值,若某个词在多篇文档中出现的频率都比较高,就降低该词的权重系数值。这个权重系数就称为“逆文档频率”(Inverse Document Frequency,缩写为IDF),它的大小与一个词的常见程度成反比。
下面给出IDF的计算公式:

从公式中可以看出,若一个词在多个文档中的词频都很高,其分母值就越大,逆文档频率就越小,分母加1是为了避免分母为零(即所有文档都不包含该词)。
log是对比值进行对数转换,主要是缩小数据的绝对值,方便计算。
下面给出IF的计算公式:

TF-IDF计算公式:

从TF-IDF计算公式可以看出,TF-IDF与一个词在文档中的出现次数成正比,与该词在整个语料库中的出现次数成反比。
在项目根目录下建立models目录,在models目录下建立tifmodel.py模块文件,代码如下:
""" 模块:IF_IDF模型 功能: 建立IF_IDF数据 """ import math class TifModel(): def __init__(self, corpus,wordnum): self.corpus = corpus self.wordnum = wordnum # 输出IF-IDF模型数据 def toTfIdfMode(self): tfmodes = [] # 文档总数 self.docnum = len(self.corpus) # 遍历文档 for text in self.corpus: tfmode = [] # 遍历单词 for word in text: if word[1] != 0: idf = self.getTF_IDF(word[0],word[1]) tfmode.append((word[0],idf)) else: tfmode.append((word[0],0)) tfmodes.append(tfmode) return tfmodes # 计算TF-IDF def getTF_IDF(self,word,count): idf = (count/self.wordnum) * math.log10(self.docnum / (self.getWordInDoc(word)+1)) return idf # 计算包含单词的文档数量 def getWordInDoc(self,word): count = 0 # 遍历文档 for text in self.corpus: if(text[word][1] > 0 ): count += 1 return count
该模块传入词袋数据,计算词袋内所有词的TF-IDF值,将词频项替换为TF-IDF值,并返回处理后的词袋数据。
支持TF-IDF模型数据的测试程序代码:
# 相似性分析测试程序
#导入db模块#
from db import readnews
#导入路径模块
from tool import participle as fc
# 导入csv模块
import csv
#导入路径模块
import tool.filepath as path
#导入字典模块
from corpora.dictionary import Dictionary
#导入分析模块
from similarities.similarity import Similarity
#导入IF_IDF模型模块
from models.tifmodel import TifModel
#导入时间模块
import datetime
# 计算时间间隔
def get_time_differ(t1,t2):
duringtime = t2 - t1
return duringtime.total_seconds()
# 程序入口
if __name__ == '__main__':
starttime = datetime.datetime.now()
# 读取前100条语料数据
t1 = datetime.datetime.now()
data = readnews.query_database_record_limit(0,6)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("从读取数据库100条新闻条目,耗时:%.3f秒" % (runsecond))
if data == None:
print("数据库读取发生错误")
else:
texts = []
t1 = datetime.datetime.now()
# 中文分词
for text in data:
words = fc.get_particlple(text[1])
texts.append(words)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("中文分词,耗时:%.3f秒" % (runsecond))
# 创建字典
dictionary = Dictionary()
t1 = datetime.datetime.now()
# 添加文档到字典
dictionary.add_documents(texts)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("建立字典,耗时:%.3f秒" % (runsecond))
# 提取第1条语料数据进行相似性分析
textwords = texts[3]
t1 = datetime.datetime.now()
simttext = dictionary.update_doc2bow(textwords)
# 从字典读取词袋数据
croups = dictionary.new_doc2bow(texts)
tfMode = TifModel(croups,dictionary.num_pos)
tfmodedata = tfMode.toTfIdfMode()
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("转换词袋数据,耗时:%.3f秒" % (runsecond))
# 初始化相似性分析类
# docsim = Similarity(croups)
docsim = Similarity(tfmodedata)
# 采用文档逐一分析方式
t1 = datetime.datetime.now()
sim = docsim.matrix_analysis(simttext)
# sim = docsim.one_analysis(simttext)
t2 = datetime.datetime.now()
runsecond = get_time_differ(t1,t2)
print("相似性分析,耗时:%.3f秒" % (runsecond))
print(sim)
endtime = datetime.datetime.now()
runsecond = get_time_differ(starttime,endtime)
print("总耗时:%.3f秒" % (runsecond))程序运行结果如下图所示:

从输出结果可以看出,在相同测试数据的情况下,使用IF-IDF模型耗费时间为3.606秒,比不使用IF-IDF模型增加了0.6秒。