1 TF-IDF算法介绍
TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术。
TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
TF-IDF的主要思想是:如果某个单词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
1.1 TF是词频(Term Frequency)
词频(TF)表示词条(关键字)在文本中出现的频率。
这个数字通常会被归一化(一般是词频除以文章总词数), 以防止它偏向长的文件。
公式如下所示:
t
f
i
j
=
n
i
,
j
∑
k
n
k
,
j
t f_{i j}=\frac{n_{i, j}}{\sum_{k} n_{k, j}}
tfij=∑knk,jni,j
即:
T
F
w
=
在某一类中词条
w
出现的次数
该类中所有的词条数目
T F_{w}=\frac{\text { 在某一类中词条 } w \text { 出现的次数 }}{\text { 该类中所有的词条数目 }}
TFw= 该类中所有的词条数目 在某一类中词条 w 出现的次数
其中 n i , j n_{i,j} ni,j是该词在文件 d j d_{j} dj中出现的次数,分母则文件 d j d_{j} dj中所有词汇出现的次数之和
IDF是逆向文件频率(Inverse Document Frequency)
逆向文件频率 (IDF) :某一特定词语的IDF,可以由总文件数目除以包含该词语的文件的数目,再将得到的商取对数得到。
如果包含词条 t t t的文档越少, I D F IDF IDF越大,则说明词条具有很好的类别区分能力。
公式如下所示:
i
d
f
i
=
log
∣
D
∣
∣
{
j
:
t
i
∈
d
j
}
∣
i d f_{i}=\log \frac{|D|}{\left|\left\{j: t_{i} \in d_{j}\right\}\right|}
idfi=log∣{j:ti∈dj}∣∣D∣
其中, ∣ D ∣ |D| ∣D∣ 是语料库中的文件总数。 ∣ { j : t i ∈ d j } ∣ \left|\left\{j: t_{i} \in d_{j}\right\}\right| ∣{j:ti∈dj}∣表示包含词语 t i t_{i} ti的文件数目(即 n i , j ≠ 0 n_{i,j}≠0 ni,j=0 的文件数目)。如果该词语不在语料库中,就会导致分母为零,因此一般情况下使用 1+ ∣ { j : t i ∈ d j } ∣ \left|\left\{j: t_{i} \in d_{j}\right\}\right| ∣{j:ti∈dj}∣
即:
I
D
F
=
log
(
语料库的文档总教
包含词条
w
的文档数
+
1
)
,
I D F=\log \left(\frac{\text { 语料库的文档总教 }}{\text { 包含词条 } w \text { 的文档数 }+1}\right),
IDF=log( 包含词条 w 的文档数 +1 语料库的文档总教 ), 分母之所以要加
1
,
1,
1, 是为了避免分母为 0
TF-IDF实际上是:TF * IDF
某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的 T F − I D F TF-IDF TF−IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。
公式:
T
F
−
I
D
F
=
T
F
∗
I
D
F
T F-I D F=T F * I D F
TF−IDF=TF∗IDF
注: TF-IDF算法非常容易理解,并且很容易实现,但是其简单结构并没有考虑词语的语义信息,无法处理一词多义与一义多词的情况。
2 TF-IDF应用
- 搜索引擎
- 关键词提取
- 文本相似性
- 文本摘要
3 python实现TF-IDF方法
# -*- coding: utf-8 -*-
from collections import defaultdict
import math
import operator
"""
函数说明:创建数据样本
Returns:
dataset - 实验样本切分的词条
classVec - 类别标签向量
"""
def loadDataSet():
dataset = [ ['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], # 切分的词条
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid'] ]
classVec = [0, 1, 0, 1, 0, 1] # 类别标签向量,1代表好,0代表不好
return dataset, classVec
"""
函数说明:特征选择TF-IDF算法
Parameters:
list_words:词列表
Returns:
dict_feature_select:特征选择词字典
"""
def feature_select(list_words):
#总词频统计
doc_frequency=defaultdict(int)
for word_list in list_words:
for i in word_list:
doc_frequency[i]+=1
#计算每个词的TF值
word_tf={} #存储没个词的tf值
for i in doc_frequency:
word_tf[i]=doc_frequency[i]/sum(doc_frequency.values())
#计算每个词的IDF值
doc_num=len(list_words)
word_idf={} #存储每个词的idf值
word_doc=defaultdict(int) #存储包含该词的文档数
for i in doc_frequency:
for j in list_words:
if i in j:
word_doc[i]+=1
for i in doc_frequency:
word_idf[i]=math.log(doc_num/(word_doc[i]+1))
#计算每个词的TF*IDF的值
word_tf_idf={}
for i in doc_frequency:
word_tf_idf[i]=word_tf[i]*word_idf[i]
# 对字典按值由大到小排序
dict_feature_select=sorted(word_tf_idf.items(),key=operator.itemgetter(1),reverse=True)
return dict_feature_select
if __name__=='__main__':
data_list,label_list=loadDataSet() #加载数据
features=feature_select(data_list) #所有词的TF-IDF值
print(features)
print(len(features))
4 NLTK实现TF-IDF算法
from nltk.text import TextCollection
from nltk.tokenize import word_tokenize
#首先,构建语料库corpus
sents=['this is sentence one','this is sentence two','this is sentence three']
sents=[word_tokenize(sent) for sent in sents] #对每个句子进行分词
print(sents) #输出分词后的结果
corpus=TextCollection(sents) #构建语料库
print(corpus) #输出语料库
#计算语料库中"one"的tf值
tf=corpus.tf('one',corpus) # 1/12
print(tf)
#计算语料库中"one"的idf值
idf=corpus.idf('one') #log(3/1)
print(idf)
#计算语料库中"one"的tf-idf值
tf_idf=corpus.tf_idf('one',corpus)
print(tf_idf)
5 Sklearn实现TF-IDF算法
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
x_train = ['TF-IDF 主要 思想 是','算法 一个 重要 特点 可以 脱离 语料库 背景',
'如果 一个 网页 被 很多 其他 网页 链接 说明 网页 重要']
x_test=['原始 文本 进行 标记','主要 思想']
#该类会将文本中的词语转换为词频矩阵,矩阵元素a[i][j] 表示j词在i类文本下的词频
vectorizer = CountVectorizer(max_features=10)
#该类会统计每个词语的tf-idf权值
tf_idf_transformer = TfidfTransformer()
#将文本转为词频矩阵并计算tf-idf
tf_idf = tf_idf_transformer.fit_transform(vectorizer.fit_transform(x_train))
#将tf-idf矩阵抽取出来,元素a[i][j]表示j词在i类文本中的tf-idf权重
x_train_weight = tf_idf.toarray()
#对测试集进行tf-idf权重计算
tf_idf = tf_idf_transformer.transform(vectorizer.transform(x_test))
x_test_weight = tf_idf.toarray() # 测试集TF-IDF权重矩阵
print('输出x_train文本向量:')
print(x_train_weight)
print('输出x_test文本向量:')
print(x_test_weight)
6 Jieba实现TF-IDF算法
import jieba.analyse
text='关键词是能够表达文档中心内容的词语,常用于计算机系统标引论文内容特征、
信息检索、系统汇集以供读者检阅。关键词提取是文本挖掘领域的一个分支,是文本检索、
文档比较、摘要生成、文档分类和聚类等文本挖掘研究的基础性工作'
keywords=jieba.analyse.extract_tags(text, topK=5, withWeight=False, allowPOS=())
print(keywords)
注意:
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
sentence
为待提取的文本topK
为返回几个 TF/IDF 权重最大的关键词,默认值为 20withWeight
为是否一并返回关键词权重值,默认值为 FalseallowPOS
仅包括指定词性的词,默认值为空,即不筛选
7 ITF-IDF算法的不足之处
TF-IDF
采用文本逆频率 IDF
对 TF
值加权取权值大的作为关键词,但 IDF
的简单结构并不能有效地反映单词的重要程度和特征词的分布情况,使其无法很好地完成对权值调整的功能,所以 TF-IDF
算法的精度并不是很高,尤其是当文本集已经分类的情况下。
在本质上 IDF
是一种试图抑制噪音的加权,并且单纯地认为文本频率小的单词就越重要,文本频率大的单词就越无用。这对于大部分文本信息,并不是完全正确的。IDF
的简单结构并不能使提取的关键词, 十分有效地反映单词的重要程度和特征词的分布情 况,使其无法很好地完成对权值调整的功能。尤其是在同类语料库中,这一方法有很大弊端,往往一些同类文本的关键词被盖。
TF-IDF算法实现简单快速,但是仍有许多不足之处:
- 没有考虑特征词的位置因素对文本的区分度,词条出现在文档的不同位置时,对区分度的贡献大小是不一样的。
- 按照传统
TF-IDF
,往往一些生僻词的IDF(反文档频率)会比较高、因此这些生僻词常会被误认为是文档关键词。 - 传统
TF-IDF
中的IDF
部分只考虑了特征词与它出现的文本数之间的关系,而忽略了特征项在一个类别中不同的类别间的分布情况。 - 对于文档中出现次数较少的重要人名、地名信息提取效果不佳。