TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TFIDF实际上是:TF * IDF,TF词频(Term Frequency),IDF逆向文件频率(Inverse Document Frequency)。
TF-IDF的原始公式为:
公式中各个变量的含义在此不再赘述,与网上的TF-IDF公式一致。但是第二个公式由于分母可能为0,因此此次我们采用平滑处理后的TF-IDF公式:
作为源码实现所依据的公式。
# TF_IDF_weight函数功能:传入corpus,返回其特征向量值向量
# 输入的corpus格式:["我 来到 中国 旅游", "中国 欢迎 你","我 喜欢 来到 中国 天安门"]
def TF_IDF_weight(corpus):
# 词库的构建
import math
weight_long = [eve.split() for eve in corpus]
word_all = []
for eve in weight_long:
for x in eve:
if len(x)>1:
word_all.append(x)
word_all = list(set(word_all)) # 集合去重词库
# 开始计算tf-idf
weight = [[] for i in corpus]
weight_idf = [[] for i in corpus]
for word in word_all:
for i in range(len(corpus)):
temp_list = corpus[i].split()
n1 = temp_list.count(word)
n2 = len(temp_list)
tf = n1/n2
n3 = len(corpus)
n4 = 0
for eve in corpus:
temp_list_ = eve.split()
if word in temp_list_:
n4 += 1
idf = math.log(((n3+1)/(n4+1))+1,10)
weight_idf[i].append(idf)
weight[i].append(tf*idf)
# L2范式归一化过程
l2_weight = [[] for i in range(len(corpus))]
for e in range(len(weight)):
all2plus = 0
for ev in weight[e]:
all2plus += ev**2
for ev in weight[e]:
l2_weight[e].append(ev/(all2plus**0.5))
return l2_weight # 返回最终结果
对源码的几点说明:
a.在构建词库的过程中,词的前后顺序没有要求,但是词语不能有重复。
b.在得到tf-idf计算结果之后,需要对其进行归一化操作,才能为分类等后续操作使用。
c.在此处将长度小于1的词语去掉了,如“我”,“你”。
使用分完词的汉语语料corpus,传入上面的函数TF_IDF_weight中:
corpus = ["我 来到 中国 旅游", "中国 欢迎 你","我 喜欢 来到 中国 天安门"]
result_list = TF_IDF_weight(corpus)
for weight in result_list:
print(weight)
输出结果:
[0.0, 0.44692991362032153, 0.5463237392780342, 0.7083671535387552, 0.0, 0.0]
[0.8457366985068379, 0.5336004467752572, 0.0, 0.0, 0.0, 0.0]
[0.0, 0.3646999329959496, 0.44580643415615906, 0.0, 0.5780357178140985, 0.5780357178140985]
使用同样的语料数据,调用sklearn下的方法求TF-IDF:
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer() # 实例化
transformer = TfidfTransformer()
corpus = ["我 来到 中国 旅游", "中国 欢迎 你","我 喜欢 来到 中国 天安门"]
result_list2 = transformer.fit_transform(vectorizer.fit_transform(corpus)).toarray().tolist()
for weight in result_list2:
print(weight)
输出结果:
[0.4254405389711991, 0.0, 0.0, 0.7203334490549893, 0.5478321549274363, 0.0]
[0.5085423203783267, 0.0, 0.0, 0.0, 0.0, 0.8610369959439764]
[0.34520501686496574, 0.5844829010200651, 0.5844829010200651, 0.0, 0.444514311537431, 0.0]
对于同一个语料数据corpus而言,现在按照第一句话 “我 来到 中国 旅游” 对比两种方法得到的向量值。
词语 | 自实现的TF-IDF | sklearn中的TF-IDF |
---|---|---|
我 | 去掉 | 去掉 |
来到 | 0.5463237392780342 | 0.5478321549274363 |
中国 | 0.44692991362032153 | 0.4254405389711991 |
旅游 | 0.7083671535387552 | 0.7203334490549893 |
可以看到二者得到的向量值非常类似,但是不完全一致。除了这一点以外,sklearn中的TF-IDF方法运行速度较快。