TF-IDF介绍及相关代码实现

一、TF-IDF介绍

TF-IDF(词频-逆向文件频率)是一种用于信息检索与文本挖掘的常用加权技术。

  • TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
  • 字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

TF-IDF的主要思想是:如果某个单词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。

1.1 TF(Term Frequency,词频)
  • 词频(TF)表示词条(关键字)在文本中出现的频率。
1.2 IDF(Inverse Document Frequency,逆向文件频率)
  • 某一特定词语的IDF,可以由总文件数目除以包含该词语的文件的数目,再将得到的商取对数得到。
  • 如果包含词条t的文档越少, IDF越大,则说明词条具有很好的类别区分能力。
1.3 TF-IDF(词频-逆向文件频率)
  • 某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。

TF-IDF(w) = \frac{在某一类词条w出现的次数}{该词条所有词数} log{ \frac{语料库中文档总数}{包含词语w的文档数目+1}}

二、基于sklearn的TF-IDF用于词向量获取

2.1、库引用
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
2.2、TF-IDF训练
x_train = ['TF-IDF 主要 思想 是','算法 一个 重要 特点 可以 脱离 语料库 背景',
           '如果 一个 网页 被 很多 其他 网页 链接 说明 网页 重要']
x_test=['原始 文本 进行 标记','主要 思想']

# max_features为维度词信息
#该类会将文本中的词语转换为词频矩阵,矩阵元素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)

2.3、向量结果
输出x_train文本向量:
[[0.70710678 0.         0.70710678 0.         0.         0.
  0.         0.         0.         0.        ]
 [0.         0.3349067  0.         0.44036207 0.         0.44036207
  0.44036207 0.44036207 0.         0.3349067 ]
 [0.         0.22769009 0.         0.         0.89815533 0.
  0.         0.         0.29938511 0.22769009]]
输出x_test文本向量:
[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]]

三、基于原始代码的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))

改进版:速度从上述代码3小时变成1分钟

def feature_select(list_words):
    
    print("1、总词频统计:")
    #总词频统计
    doc_frequency=defaultdict(int)
    for word_list in tqdm(list_words):
        for i in word_list:
            doc_frequency[i]+=1
    
    print("2、TF计算:")
    #计算每个词的TF值
    n = sum(doc_frequency.values())
    word_tf={}  #存储没个词的tf值
    for i in tqdm(doc_frequency):
        word_tf[i]=doc_frequency[i]/n
   
    print("3、IDF计算:")
    #计算每个词的IDF值
    doc_num=len(list_words)
    word_idf={} #存储每个词的idf值
    word_doc=defaultdict(int) #存储包含该词的文档数
    for i in tqdm(range(len(list_words))):
        for word in list_words[i]:
            word_doc[word]+=1
    
    for i in tqdm(doc_frequency):
        word_idf[i]=math.log(doc_num/(word_doc[i]+1))

    print("4、TF计算:")
    #计算每个词的TF*IDF的值
    word_tf_idf={}
    for i in tqdm(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

四、基于sklearn的TF-IDF用于权值获取

4.1、库引用
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
4.2、数据集
corpus = [
  "帮我 查下 明天 北京 天气 怎么样",
  "帮我 查下 今天 北京 天气 好不好",
  "帮我 查询 去 北京 的 火车",
  "帮我 查看 到 上海 的 火车",
  "帮我 查看 特朗普 的 新闻",
  "帮我 看看 有没有 北京 的 新闻",
  "帮我 搜索 上海 有 什么 好玩的",
  "帮我 找找 上海 东方明珠 在哪"
]
4.3、字典构造
# 步骤1
vectoerizer = CountVectorizer(min_df=1, max_df=1.0, token_pattern='\\b\\w+\\b')

# 步骤2
vectoerizer.fit(corpus)

# 步骤3
bag_of_words = vectoerizer.get_feature_names()

print("Bag of words(词袋):")
print(bag_of_words)
# 字典大小
print(len(bag_of_words))

# 步骤4
X = vectoerizer.transform(corpus)
# 每句话种每个词出现的次数
print("Vectorized corpus:")
print(X.toarray())

# 步骤5:字典
print("index of `的` is : {}".format(vectoerizer.vocabulary_.get('上海')))
4.4、TF-IDF权值获取
from sklearn.feature_extraction.text import TfidfTransformer


# 步骤1
tfidf_transformer = TfidfTransformer()
# 步骤2
tfidf_transformer.fit(X.toarray())

# 步骤3,tf-idf权值
word_list = {}
for idx, word in enumerate(vectoerizer.get_feature_names()):
#       print("{}\t{}".format(word, tfidf_transformer.idf_[idx]))
    word_list[word] = tfidf_transformer.idf_[idx]
    

dic = sorted(word_list.items(),key=lambda x:-x[1])
print(dic)

# 步骤4 # 句子向量
# tfidf = tfidf_transformer.transform(X)
# print(tfidf.toarray())
4.5、结果
[('东方明珠', 2.504077396776274), ('什么', 2.504077396776274), ('今天', 2.504077396776274), ('到', 2.504077396776274), ('去', 2.504077396776274), ('在哪', 2.504077396776274), ('好不好', 2.504077396776274), ('好玩的', 2.504077396776274), ('怎么样', 2.504077396776274), ('找找', 2.504077396776274), ('搜索', 2.504077396776274), ('明天', 2.504077396776274), ('有', 2.504077396776274), ('有没有', 2.504077396776274), ('查询', 2.504077396776274), ('特朗普', 2.504077396776274), ('看看', 2.504077396776274), ('天气', 2.09861228866811), ('新闻', 2.09861228866811), ('查下', 2.09861228866811), ('查看', 2.09861228866811), ('火车', 2.09861228866811), ('上海', 1.8109302162163288), ('北京', 1.587786664902119), ('的', 1.587786664902119), ('帮我', 1.0)]

五、基于gensim的TF-IDF用于权值获取

gensim原始地址:models.tfidfmodel – TF-IDF model — gensim (radimrehurek.com)

5.1 语料库
corpus = [
    'this is the first document',
    'this is the second second document',
    'and the third one',
    'is this the first document'
]
5.2 分词
[输入]:
word_list = []
for i in range(len(corpus)):
    word_list.append(corpus[i].split(' '))
print(word_list)
    
[输出]:
[['this', 'is', 'the', 'first', 'document'],
 ['this', 'is', 'the', 'second', 'second', 'document'],
 ['and', 'the', 'third', 'one'],
 ['is', 'this', 'the', 'first', 'document']]
5.3 字典和词袋模型构建
from gensim import corpora
# 赋给语料库中每个词(不重复的词)一个整数id
dictionary = corpora.Dictionary(word_list)
new_corpus = [dictionary.doc2bow(text) for text in word_list]
print(new_corpus)

# 元组中第一个元素是词语在词典中对应的id,第二个元素是词语在文档中出现的次数
[输出]:
[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)], 
 [(0, 1), (2, 1), (3, 1), (4, 1), (5, 2)], 
 [(3, 1), (6, 1), (7, 1), (8, 1)], 
 [(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)]]

通过下面的方法可以看到语料库中每个词对应的id

 [输入]:
 print(dictionary.token2id)

 [输出]:
 {'document': 0, 'first': 1, 'is': 2, 'the': 3, 'this': 4, 'second': 5, 'and': 6,
 'one': 7,   'third': 8}
5.4 TF-IDF模型训练
[输入]:
# 训练模型并保存
from gensim import models
tfidf = models.TfidfModel(new_corpus)
tfidf.save("my_model.tfidf")

# 载入模型
tfidf = models.TfidfModel.load("my_model.tfidf")

# 使用这个训练好的模型得到单词的tfidf值
print(list(tfidf[new_corpus]))

[输出]:
[[(0, 0.33699829595119235),
  (1, 0.8119707171924228),
  (2, 0.33699829595119235),
  (4, 0.33699829595119235)],
 [(0, 0.10212329019650272),
  (2, 0.10212329019650272),
  (4, 0.10212329019650272),
  (5, 0.9842319344536239)],
 [(6, 0.5773502691896258), (7, 0.5773502691896258), (8, 0.5773502691896258)],
 [(0, 0.33699829595119235),
  (1, 0.8119707171924228),
  (2, 0.33699829595119235),
  (4, 0.33699829595119235)]]
核心代码
# TF-IDF
dictionary = corpora.Dictionary(Descartes_doc)
new_corpus = [dictionary.doc2bow(text) for text in Descartes_doc]
tfidf = models.TfidfModel(new_corpus)
corpus_tfidf = tfidf[new_corpus]

结论:

  • gensim训练出来的tf-idf值左边是词的id,右边是词的tfidf值
  • gensim有自动去除停用词的功能,比如the
  • gensim会自动去除单个字母,比如i
  • gensim会去除没有被训练到的词,比如name
  • 所以通过gensim并不能计算每个单词的tfidf值

参考文献

  • TF-IDF算法介绍及实现_Asia-Lee-CSDN博客_tf-idf
  • 使用不同的方法计算TF-IDF值 - (jianshu.com)
  • models.tfidfmodel – TF-IDF model — gensim (radimrehurek.com)

你可能感兴趣的:(TF-IDF介绍及相关代码实现)