TF-IDF介绍(原来+代码)

TF-IDF原理

    对于一篇比较长的文章,想要不加人为干预的迅速了解文章的关键词,该怎么做到呢?这时候要送到经典算法IF-IDF,TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术。
    直观上理解,如果一个词很关键,那么这个词在文本中出现的次数就会比较多,此时我们就用 TF(词频) 来表示。而你又要问了,那么文章中出现最多的一定是一些类似 “的”,‘是’,‘在’等停用词 需要将这些词事先过滤掉在对文本进行处理。还有一个问题,我们要考虑词语的关键程度,如果文章中有些词出现的次数一样多,比如 “中国”,“蜜蜂”,“养殖” ,是否就能简单的认为这三个词语重要程度一样呢?答案是否定的,我们很容易看出 “中国” 是一个很常见的词语,在很多文献中都是经常出现的词语,就算给你这个词语,你并不知道这篇文章是干什么的。而 “蜜蜂”,“养殖” 却不常见,很能反应文章的内容,其俩关键性要大于 中国 ,所以还需要采取一种方法来解决。
    所以,我们需要一个重要性调整系数,衡量一个词是不是常见词。如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性,正是我们所需要的关键词。
    用统计语言来表示,就是在 词频的基础上,对每个词分配一个表示“重要性”的 权重 ,比如最常见的词 “是”,“的” 等停用词给与最小的权重,“中国” 给与较小的权重,而 “蜜蜂”,“养殖” 这类少见的词语给予较大的权重。我们把这个权重叫做 “逆文档频率(IDF)” ,它的大小与一个词的常见程度成 反比
    我们已经了解了什么是 频率(TF)逆文档频率(IDF) 的概念。将两个值相乘,就得到了一个词的 TF-IDF值 ,值越大,说明词对文章的重要性越高。根绝词语的TF-IDF值排名来选择文章的关键词。

I F − I D F IF-IDF IFIDF 的计算步骤如下:

     1 、 1、 1 计算词频
    词频(TF) = 该词在文章中出现的次数
    考虑到文章有长短之分,这里对文章进行 “词频”标准化
    词频(TF) = 该词在文章出现的次数/文章总词数
     2 、 2、 2 计算逆文档频率
    这是,需要一个语料库(corpus),用来模拟语言的使用环境。计算公式为
    逆文档频率(IDF) = log10(语料库的文档总数/包含该词的文档数+1)
     分母加1是为了防止所有文档都不包含该词,避免分母为0
     3 、 3、 3 计算TF-IDF
    TF-IDF = 词频(TF) X 逆文档频率(IDF)
    从最终的结果来看,TF-IDF值与一个词在文档中出现的次数成 正比 ,与该词在整个语言中的出现次数成 反比 ,所以提取文章关键词就要计算TF-IDF值,按照大小顺序进行选择。
下面以 《中国的蜜蜂养殖》 为例子,为大家计算一下。假定文章长度为1000个词,“中国”,“蜜蜂”,“养殖” 各出现了15次,则这三个词的 “词频(TF)” 都为0.015,然后搜索Google发现,包含 “的” 的网页共有250亿张,包含 “中国” 的网页共有62.3亿张,包含 “蜜蜂” 的网页为0.484亿张,包含 “养殖” 的网页为0.973亿张,则他们的 逆文档频率(IDF)IF-IDF值 如下:

包含该词的文档数(亿) IDF TF-IDF
中国 62.3 0.603 0.009
蜜蜂 0.484 2.713 0.041
养殖 0.973 2.410 0.036
250 0.002 3e-5

    从结果来看,“蜜蜂” 的TF-IDF值最高,**"养殖"其次,“的”**最低,近乎于 0。所以,如果只选择一个词,"蜜蜂"就是这篇文章的关键词。
    TF-IDF算法的优点是简单快速,结果比较符合实际情况。缺点是,单纯以"词频"衡量一个词的重要性,不够全面,有时重要的词可能出现次数并不多。而且,这种算法无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的。(一种解决方法是,对全文的第一段和每一段的第一句话,给予较大的权重。)

使用三种方法计算TF-IDF值

1 、 g e n s i m 库 来 计 算 T F − I D F 值 1、gensim库来计算TF-IDF值 1gensimTFIDF
首 先 构 建 语 料 库 为 首先构建语料库为

corpus = [
	'this is the first document',
	'this is the second second document',
	'and the third one',
	'is this the first document'
]

开 始 处 理 开始处理
1 ) 对 文 本 进 行 分 词 1)对文本进行分词 1

seg_list = []
for i in range(len(corpus)):
    seg_list.append(corpus[i].split(' '))
seg_list
结果为:
[['this', 'is', 'the', 'first', 'document'],
 ['this', 'is', 'the', 'second', 'second', 'document'],
 ['and', 'the', 'third', 'one'],
 ['is', 'this', 'the', 'first', 'document']]

2 ) 对 每 个 词 分 配 I d 以 及 计 算 词 频 2)对每个词分配Id以及计算词频 2Id

from gensim import corpora
dictionary = corpora.Dictionary(seg_list)  #生成字典,且对词语编号Id
for key,value in dictionary.items():
    print(key,value)

结果为:
0 document
1 first
2 is
3 the
4 this
5 second
6 and
7 one
8 third
#词频统计
new_corpus = [dictionary.doc2bow(text) for text in seg_list]
print(new_corpus)
结果为:
[[(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,第二个数表示词频(词语出现的个数),比如(0,1)表示第一个文本中document出现了1词,(5,2)表示第二个文本中second出现了2次。

3 ) 训 练 g e n s i m 模 型 并 且 保 存 它 以 便 后 面 的 使 用 3)训练gensim模型并且保存它以便后面的使用 3gensim便使

from gensim import models
tfidf = models.TfidfModel(new_corpus) #训练的模型
#载入模型得到单词的tfidf值
tfidf_vec = []
for i in range(len(corpus)):
    string = corpus[i]
    string_bow = dictionary.doc2bow(string.lower().split())
    string_tfidf = tfidf[string_bow]
    tfidf_vec.append(string_tfidf)
print(tfidf_vec)
结果:
[[(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)]]

g e n s i m 方 法 总 结 : gensim方法总结: gensim
1、gensim训练出来的tf-idf值左边是词的id,右边是词的tfidf值
2、gensim有自动去除停用词的功能,比如the
3、gensim有自动去除单个字母,比如i
4、所以通过gensim并不能计算每个单词的tfidf值

2 、 s k l e a r n 库 提 取 文 本 t f i d f 特 征 2、sklearn库提取文本tfidf特征 2sklearntfidf
代 码 代码

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vec = TfidfVectorizer()
tfidf_matrix = tfidf_vec.fit_transform(corpus)

#得到语料库中不重复的词
print('不重复词:\n',tfidf_vec.get_feature_names())

#得到每个单词对应的id值
print('词语对应的id:\n',tfidf_vec.vocabulary_)

#得到每个句子所对应的向量
#向量里数字的顺序是按照词语的id顺序来的
print(tfidf_matrix.toarray())

结果为:
不重复词:
 ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
词语对应的id:
 {'this': 8, 'is': 3, 'the': 6, 'first': 2, 'document': 1, 'second': 5, 'and': 0, 'third': 7, 'one': 4}
[[0.         0.43877674 0.54197657 0.43877674 0.         0.
  0.35872874 0.         0.43877674]
 [0.         0.27230147 0.         0.27230147 0.         0.85322574
  0.22262429 0.         0.27230147]
 [0.55280532 0.         0.         0.         0.55280532 0.
  0.28847675 0.55280532 0.        ]
 [0.         0.43877674 0.54197657 0.43877674 0.         0.
  0.35872874 0.         0.43877674]]

3 、 自 定 义 p y t h o n 提 取 文 本 t f i d f 特 征 3、自定义python提取文本tfidf特征 3pythontfidf
基 于 原 来 的 语 料 库 以 及 分 词 处 理 基于原来的语料库以及分词处理
1 ) 词 频 统 计 1)词频统计 1

from collections import Counter
countlist = []
for i in range(len(seg_list)):
    count = Counter(seg_list[i])
    countlist.append(count)
print(countlist)

结果:
[Counter({'this': 1, 'is': 1, 'the': 1, 'first': 1, 'document': 1}), 
Counter({'second': 2, 'this': 1, 'is': 1, 'the': 1, 'document': 1}),
 Counter({'and': 1, 'the': 1, 'third': 1, 'one': 1}), 
Counter({'is': 1, 'this': 1, 'the': 1, 'first': 1, 'document': 1})]

2 ) 定 义 p y t h o n 计 算 t f i d f 公 式 的 函 数 2)定义python计算tfidf公式的函数 2pythontfidf

# word可以通过count得到,count可以通过countlist得到
# count[word]可以得到每个单词的词频, sum(count.values())得到整个句子的单词总数
def tf(word, count):
    return count[word] / sum(count.values())

# 统计的是含有该单词的句子数
def n_containing(word, count_list):
    return sum(1 for count in count_list if word in count)
 
# len(count_list)是指句子的总数,n_containing(word, count_list)是指含有该单词的句子的总数,加1是为了防止分母为0
def idf(word, count_list):
    return math.log(len(count_list) / (1 + n_containing(word, count_list)))

# 将tf和idf相乘
def tfidf(word, count, count_list):
    return tf(word, count) * idf(word, count_list)

3 ) 计 算 每 个 单 词 的 t f i d f 值 3)计算每个单词的tfidf值 3tfidf

import math
for i, count in enumerate(countlist):
    print("Top words in document {}".format(i + 1))
    scores = {word: tfidf(word, count, countlist) for word in count}
    sorted_words = sorted(scores.items(), key=lambda x: x[1], reverse=True)
    for word, score in sorted_words[:]:
        print("\tWord: {}, TF-IDF: {}".format(word, round(score, 5)))

结果为:
Top words in document 1
	Word: first, TF-IDF: 0.05754
	Word: this, TF-IDF: 0.0
	Word: is, TF-IDF: 0.0
	Word: document, TF-IDF: 0.0
	Word: the, TF-IDF: -0.04463
Top words in document 2
	Word: second, TF-IDF: 0.23105
	Word: this, TF-IDF: 0.0
	Word: is, TF-IDF: 0.0
	Word: document, TF-IDF: 0.0
	Word: the, TF-IDF: -0.03719
Top words in document 3
	Word: and, TF-IDF: 0.17329
	Word: third, TF-IDF: 0.17329
	Word: one, TF-IDF: 0.17329
	Word: the, TF-IDF: -0.05579
Top words in document 4
	Word: first, TF-IDF: 0.05754
	Word: is, TF-IDF: 0.0
	Word: this, TF-IDF: 0.0
	Word: document, TF-IDF: 0.0
	Word: the, TF-IDF: -0.04463

3、联合词袋模型和TF-IDF

    tf-idf的主要作用就是找出某个词或某些词用于区别于其他文本,而 词袋模型 恰好又是找出文本中出现频率高的词语,那么我们试想:如果我先用词袋模型筛选出一些高热度词汇,再用tf-idf计算其权值,我们将得到词袋模型中的词汇的tf-idf值,值越高说明该词却分每条语句的效果越好。

import numpy as np
from sklearn import preprocessing
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

vec=CountVectorizer(min_df=3,ngram_range=(1,1))
content=[
    'alert(1)X',
    '\'>