背景
最近看吴军的《数学之美》了解了一些文本处理方法,其中TF-IDF给了我深刻的印象(因为之前也做过这方面的项目),正好这次做个记录。
信息熵
TF-IDF是在熵的基础上发展的概念,因此先介绍熵。
熵反映的是一个系统的混乱程度,一个系统越混乱,其熵就越大;越是整齐,熵就越小。熵增加原理指的是一个孤立系统内的自发过程,都是从朝越来越混乱的方向发展,意思是向熵增加的方向发展。
在熵的基础上发展出了信息熵的概念,用来衡量数据的信息量。下面介绍信息熵公式:
其中
P
(
x
i
)
P(x_{i})
P(xi) 代表随机事件X为
x
i
x_{i}
xi 的概率。
1,事件发生的概率越低,其发生时所能给出的信息量越大。
日常发生的事情没什么信息量,罕见的事情信息量就大了(如海南下雪了)
2,
0
<
=
P
(
x
i
)
<
=
1
0<=P(x_{i})<=1
0<=P(xi)<=1,因此负号是为了确保信息一定是正数或者是0
3,信息熵还可以作为一个系统复杂程度的度量,如果系统越复杂,出现不同情况的种类越多,那么他的信息熵是比较大的。如果一个系统越简单,出现情况种类很少,此时的信息熵较小。
相对熵
用于衡量两个取值为正值的函数的相关性。公式如下:
1,两个函数完全相同,相对熵为0
2,相对熵越大,函数差异越大;反正差异越小。
3,对于概率分布或者概率密度函数,取值均大于0,相对熵可以衡量两个随机分布的差异性。
TF-IDF实际就是一种相对熵
TF-IDF
TF-IDF算法在文本处理中有很重要的作用。下面作介绍:
1,TF(Term Frequency)
在搜索引擎中,如何对结果排序?一开始的做法是根据网页自身的质量以及网页中出现关键词的频率进行排序。但是这个办法有一个问题,篇幅长的网页会比篇幅短的网页占便宜,因为前者中含有更多的关键词。因此我们可以对数据进行归一化,也就是将关键词出现的次数除以网页的总字数,得到的就是TF。
如:输入
w
1
w_1
w1、
w
2
w_2
w2、
w
3
w_3
w3…
w
n
w_n
wnn个关键词进行查询,则一个网页的相关性可以用TF衡量,记为:
T
F
1
+
T
F
2
+
.
.
.
.
.
.
+
T
F
n
TF_1+TF_2+......+TF_n
TF1+TF2+......+TFn
2,IDF(Inverse Document Frequency)
不同关键词应该有不同的权重,如一些无意义的停止词(的,是,和等)权重为0;而词预测主题的能力越强,其权重应该越大。
什么样的词预测能力强?一个词如果只在很少的网页中出现,那么就很容易通过这个词预测主题;那些在网页中经常出现的词,看到了也很难预测出网页的主题。
据此可以得到IDF的公式:
I
D
F
=
l
o
g
D
D
w
IDF=log^\frac{D}{D_{w}}
IDF=logDwD
D
是
网
页
总
数
,
D
w
是
出
现
关
键
词
w
的
网
页
数
D是网页总数,D_{w}是出现关键词w的网页数
D是网页总数,Dw是出现关键词w的网页数
3,TF-IDF
TF-IDF是TF(频率)和IDF(预测主题能力)的加权求和:
T
F
1
∗
I
D
F
1
+
T
F
2
∗
I
D
F
2
+
T
F
3
∗
I
D
F
3......
+
T
F
n
∗
I
D
F
n
TF{1}*IDF{1}+TF{2}*IDF{2}+TF{3}*IDF{3}......+TF{n}*IDF{n}
TF1∗IDF1+TF2∗IDF2+TF3∗IDF3......+TFn∗IDFn
代码
最后附上之前写的TF-IDF代码。
# -*- coding: utf-8 -*-
from collections import defaultdict
import math
import operator
import pandas as pd
import jieba
import re
import csv
#对文本进行分词
def list_build(csv_data_list):
data_list=[]
for one_list in csv_data_list:
seg_list=jieba.cut(str(one_list))
z=[x for x in seg_list]
zz=str(z)
#去特殊符号
zz = re.sub(r'([\d]+)',' ',zz).lower()
zz = re.sub("[0-9\s+\.\!\/_,$%^*()?;;:-【】+\"\']+|[+——!,;:。?、~@#¥%……&*()]+", " ", zz)
#移除字符串开头的空格
zz = zz.strip()
#根据空格将字符串分为列表中的元素
zz=zz.split(' ')
#去除停用词
for i in range(len(zz)):
for one in zz:
if one in stop_words:
zz.remove(one)
#去除空元素
while '' in zz:
zz.remove('')
data_list.append(zz)
return data_list
"""
函数说明:特征选择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__':
f=open('DATA.txt',encoding="utf-8")
data=pd.read_csv(f)
csv_data_list = data['text']
stop_words=['二哈','摊手','分享','图片'......]
data_list=list_build(csv_data_list)
features=feature_select(data_list) #所有词的TF-IDF值
with open('结果.txt','w',encoding="utf-8",newline='') as f1:
header=['text','num']
writer = csv.writer(f1, delimiter=',')
writer.writerow(header)
for i in range(len(features)):
header=[features[i][0],str(features[i][1])]
writer.writerow(header)