对于一篇比较长的文章,想要不加人为干预的迅速了解文章的关键词,该怎么做到呢?这时候要送到经典算法IF-IDF,TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术。
直观上理解,如果一个词很关键,那么这个词在文本中出现的次数就会比较多,此时我们就用 TF(词频) 来表示。而你又要问了,那么文章中出现最多的一定是一些类似 “的”,‘是’,‘在’等停用词 需要将这些词事先过滤掉在对文本进行处理。还有一个问题,我们要考虑词语的关键程度,如果文章中有些词出现的次数一样多,比如 “中国”,“蜜蜂”,“养殖” ,是否就能简单的认为这三个词语重要程度一样呢?答案是否定的,我们很容易看出 “中国” 是一个很常见的词语,在很多文献中都是经常出现的词语,就算给你这个词语,你并不知道这篇文章是干什么的。而 “蜜蜂”,“养殖” 却不常见,很能反应文章的内容,其俩关键性要大于 中国 ,所以还需要采取一种方法来解决。
所以,我们需要一个重要性调整系数,衡量一个词是不是常见词。如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性,正是我们所需要的关键词。
用统计语言来表示,就是在 词频的基础上,对每个词分配一个表示“重要性”的 权重 ,比如最常见的词 “是”,“的” 等停用词给与最小的权重,“中国” 给与较小的权重,而 “蜜蜂”,“养殖” 这类少见的词语给予较大的权重。我们把这个权重叫做 “逆文档频率(IDF)” ,它的大小与一个词的常见程度成 反比。
我们已经了解了什么是 频率(TF) 和 逆文档频率(IDF) 的概念。将两个值相乘,就得到了一个词的 TF-IDF值 ,值越大,说明词对文章的重要性越高。根绝词语的TF-IDF值排名来选择文章的关键词。
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算法的优点是简单快速,结果比较符合实际情况。缺点是,单纯以"词频"衡量一个词的重要性,不够全面,有时重要的词可能出现次数并不多。而且,这种算法无法体现词的位置信息,出现位置靠前的词与出现位置靠后的词,都被视为重要性相同,这是不正确的。(一种解决方法是,对全文的第一段和每一段的第一句话,给予较大的权重。)
1 、 g e n s i m 库 来 计 算 T F − I D F 值 1、gensim库来计算TF-IDF值 1、gensim库来计算TF−IDF值
首 先 构 建 语 料 库 为 首先构建语料库为 首先构建语料库为
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以及计算词频 2)对每个词分配Id以及计算词频
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模型并且保存它以便后面的使用 3)训练gensim模型并且保存它以便后面的使用
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特征 2、sklearn库提取文本tfidf特征
代 码 代码 代码
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特征 3、自定义python提取文本tfidf特征
基 于 原 来 的 语 料 库 以 及 分 词 处 理 基于原来的语料库以及分词处理 基于原来的语料库以及分词处理
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公式的函数 2)定义python计算tfidf公式的函数
# 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值 3)计算每个单词的tfidf值
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
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',
'\'>
点 互 信 息 P M I 点互信息PMI 点互信息PMI
点互信息PMI(Pointwise Mutual Information)这个指标常常用来衡量两个事物之间的相关性(比如两个词)。公式如下:
如果x跟y不相关,则p(x,y)=p(x)p(y)。二者相关性越大,则p(x, y)就相比于p(x)p(y)越大。
举个自然语言处理中的例子来说,我们想衡量like这个词的极性(正向情感还是负向情感)。我们可以预先挑选一些正向情感的词,比如good。然后计算like跟good的PMI。
互 信 息 M I 互信息MI 互信息MI
点互信息PMI其实就是从信息论里面的互信息这个概念里面衍生出来的。 互信息即:
其衡量的是两个随机变量之间的相关性,即一个随机变量中包含的关于另一个随机变量的信息量。
可以看出,互信息其实就是对X和Y的所有可能的取值情况的点互信息PMI的加权和。
利 用 互 信 息 进 行 筛 选 特 征 利用互信息进行筛选特征 利用互信息进行筛选特征
s k l e a r n . f e a t u r e s e l e c t i o n . m u t u a l i n f o c l a s s i f sklearn.feature_selection.mutual_info_classif sklearn.featureselection.mutualinfoclassif
from sklearn import datasets
from sklearn.feature_selection import mutual_info_classif
iris = datasets.load_iris()
x = iris.data
label = iris.target
mutual_info = mutual_info_classif(x, label, discrete_features= False)
print(mutual_info)
结果为