天天看点

Python 数据分析实例——文本挖掘

作者:昌华量化
Python 数据分析实例——文本挖掘

1.文本挖掘的概念

文本挖掘(Text Mining)是抽取有效的、新颖的、有用的、可理解的、散布在文本文件中的有价值知识,并且利用这些知识更好地组织信息的过程。

机器学习算法的空间、时间复杂度依赖于输入数据的规模,维度规约(Dimensionality Reduction)是一种用于降低输入数据维数的方法。维度规约可以分为两类:

· 特征选择(Feature Selection),从原始的d维空间中选择提供信息最多的k维(这k个维属于原始空间的子集)。

· 特征提取(Feature Extraction),将原始的d维空间映射到k维空间中(新的k维空间不输入原始空间的子集)。

在文本挖掘与文本分类的有关问题中,常采用特征选择方法。原因是文本的特征一般都是单词(Term),具有语义信息,使用特征选择找出的k维子集仍然是以单词作为特征,保留了语义信息,而特征提取则是找k维新空间,将会丧失语义信息。

2.文本的特征选择方法

对于一个语料而言,可以统计的信息包括文档频率和文档类比例,所有的特征选择方法均依赖于这两个统计量。目前,文本的特征选择方法主要有:DF、MI、IG、CHI、WLLR、WFO六种。

为了方便描述,我们首先进行一些概率上的定义:

· p(t):一篇文档x包含特征词t的概率。

· 

Python 数据分析实例——文本挖掘

:文档x不属于Ci的概率。

· p(Ci|t):已知文档x在包括某个特征词t的条件下,该文档属于Ci的概率。

· 

Python 数据分析实例——文本挖掘

:已知文档属于Ci的条件下,该文档不包括特征词t的概率。

其他的一些概率如p(Ci)、

Python 数据分析实例——文本挖掘

Python 数据分析实例——文本挖掘

等,有着类似的定义。

下面介绍其他的统计量还包括:

· Aij:包含特征词ti,并且类别属于Cj的文档数量。

· Bij:包含特征词ti,并且类别不属于Cj的文档数量。

· Cij:不包含特征词ti,并且类别属于Cj的文档数量。

· Dij:不包含特征词ti,并且类别不属于Cj的文档数量。

· Aij+Bij:包含特征词ti的文档数量。

· Cij+Dij:不包含特征词ti的文档数量。

· Aij+Cij:Cj类的文档数量数据。

· Bij+Dij:非Cj类的文档数量数据。

· Aij+Bij+Cij+Dij=N:语料中所有文档的数量。

有了这些统计量,有关概率的估算就会变得更容易,如:

Python 数据分析实例——文本挖掘
Python 数据分析实例——文本挖掘
Python 数据分析实例——文本挖掘

3.常见的6种特征选择方法的计算

(1)DF(Document Frequency)

DF指统计特征词出现的文档数量,用来衡量某个特征词的重要性。DF的定义如下:

Python 数据分析实例——文本挖掘

DF的原理是:如果某些特征词在文档中经常出现,这个词就可能很重要。而对于在文档中出现很少(如仅在语料中出现1次有可能)的特征词,携带的信息量很少,甚至是“噪声”,这些特征词对分类器学习的影响也很小。

DF特征选择方法属于无监督的学习算法(也将其改成有监督的算法,但是大部分情况下都作为无监督的算法使用),仅考虑了频率因素而没有考虑类别因素,因此DF算法将会引入一些没有意义的词。例如中文的“的”“是”“个”等常常具有很高的DF得分,但是对分类并没有多大的意义。

(2)MI(Mutual Information)

互信息法用于衡量特征词与文档类别直接的信息量。互信息法的定义如下:

Python 数据分析实例——文本挖掘

继续推导MI的定义公式:

Python 数据分析实例——文本挖掘

从上面的公式上可以看出:如果某个特征词的频率很低,互信息得分就会很高,因此互信息法倾向于“低频”的特征词。相对的,词频很高的词,得分就会变低,如果该词携带了很高的信息量,互信息法就会变得低效。

(3)IG(Information Gain)

信息增益法通过某个特征词在缺失与存在两种情况下语料中前后信息的增加来衡量某个特征词的重要性。信息增益的定义如下:

Python 数据分析实例——文本挖掘

IG与MI存在关系:

Python 数据分析实例——文本挖掘

因此,IG方式实际上就是互信息I(ti,Cj)与互信息加权。

(4)CHI(Chi-square,卡方检验)

CHI特征选择算法利用了统计学中的“假设检验”的基本思想:首先假设特征词与类别直接是不相关的,利用CHI分布计算出的检验值偏离阈值越大,就越否定原假设,接受原假设的备则假设:特征词与类别有着很高的关联度。CHI的定义如下:

Python 数据分析实例——文本挖掘

对于一个给定的语料而言,文档的总数N以及Cj类文档的数量、非Cj类文档的数量都是一个定值。因此,CHI的计算公式可以简化为:

Python 数据分析实例——文本挖掘

CHI特征选择方法综合考虑文档频率与类别比例两个因素。

(5)WLLR(Weighted Log Likelihood Ration,加权对数似然比)

WLLR特征选择方法的定义如下:

Python 数据分析实例——文本挖掘

计算公式如下:

Python 数据分析实例——文本挖掘

(6)WFO(Weighted Frequency and Odds,加权频率和比值)

WFO的算法定义如下:

如果

Python 数据分析实例——文本挖掘
Python 数据分析实例——文本挖掘

否则:

Python 数据分析实例——文本挖掘

一般来说,不同的语料文档词频与文档的类别比例起的作用应该是不一样的,WFO方法可以通过调整参数λ找出一个较好的特征选择依据。

4.文本挖掘实例

【例1】NLTK文本分析+jieba中文文本挖掘。

NLTK的全称是Natural Language Toolkit,是一套基于Python的自然语言处理工具集。

NLTK的安装:

(base) C:\Users\workspace>pip install nltk

在NLTK中集成语料与模型等的包管理器,通过在Python解释器中执行:

Python 数据分析实例——文本挖掘

便会弹出如图1所示的包管理界面,在管理器中可以下载语料、预训练的模型等。

Python 数据分析实例——文本挖掘

图1 NLTK下载

(1)NLTK自带语料库:​

>>> from nltk.corpus import brown
>>> brown.categories()
['adventure',   'belles_lettres',   'editorial',   'fiction',  'government',
'hobbies', 'humor', 'learned', 'lore', 'mystery', 'news', 'religion', 'reviews',
'romance', 'science_fiction']
>>> len(brown.sents())
57340
>>> len(brown.words())
1161192           

(2)Tokenize:把句子分成一个个的小部件,例如:​

>>> sentence="this is a good student,snoy"
>>> tokens=nltk.word_tokenize(sentence)
>>> tokens
['this', 'is', 'a', 'good', 'student', ',', 'snoy']           

(3)nltk.text类介绍。

nltk.text.Text()类用于对文本进行初级的统计与分析,它接收一个词的列表作为参数。nltk.text.Text()类提供了下列方法:

· Text(words):对象构造。

· concordance(word, width=79, lines=25):显示word出现的上下文。

· common_contexts(words):显示words出现的相同模式。

· similar(word):显示word的相似词。

· collocations(num=20, window_size=2):显示最常见的二词搭配。

· count(word):word出现的词数。

· dispersion_plot(words):绘制words文档中出现的位置图。

· vocab():返回文章去重的词典。

nltk.text.TextCollection类是Text的集合,提供下列方法。

· nltk.text.TextCollection([text1,text2,]):对象构造。

· idf(term):计算词term在语料库中的逆文档频率。

· tf(term,text):统计term在text中的词频。

· tf_idf(term,text):计算term在句子中的tf_idf,即tf*idf。

(4)使用结巴分词(中文分词)。

结巴分词的GitHub主页:

https://github.com/fxsjy/jieba

安装结巴库文件方法如下:​

pip install jieba
(base) C:\Users\workspace>pip install jieba           

· jieba.cut方法接收3个输入参数:需要分词的字符串;cut_all参数用来控制是否采用全模式;HMM参数用来控制是否使用HMM模型。

· jieba.cut_for_search方法接收两个参数:需要分词的字符串;是否使用HMM模型。该方法适用于搜索引擎构建倒排索引的分词,粒度比较细。

· 待分词的字符串可以是Unicode或UTF-8字符串、GBK字符串。注意:不建议直接输入GBK字符串,可能无法预料的错误解码成UTF-8。

· jieba.cut和jieba.cut_for_search返回的结构都是一个可迭代的generator,可以使用for循环来获得分词后得到的每一个词语(Unicode),或者用jieba.lcut和jieba.lcut_for_search直接返回list。

· jieba.Tokenizer(dictionary=DEFAULT_DICT)新建自定义分词器,可用于同时使用不同的词典。jieba.dt为默认分词器,所有全局分词相关函数都是该分词器的映射。

(5)语料库介绍。在NLTK文本分析中,我们经常用到不同的语料库:

Python 数据分析实例——文本挖掘

这些语料库的文本文件说明如下。

古藤堡语料库:

Python 数据分析实例——文本挖掘

网络和聊天文本库:

Python 数据分析实例——文本挖掘

即时聊天会话语料库,是美国海军研究生院的研究生收集的。

Python 数据分析实例——文本挖掘

布朗语料库,布朗语料库是第一个百万词级别的英语电子语料库,这个语料库包含500个不同来源的文本,按文体分类有新闻、社论等完整列表。​

>>> from nltk.corpus import brown
>>> brown.categories()
['adventure',   'belles_lettres',   'editorial',   'fiction',  'government',
'hobbies', 'humor', 'learned', 'lore', 'mystery', 'news', 'religion', 'reviews',
'romance', 'science_fiction']
#这里注意的是它是按文体分类的,例如要取得news类别的文本
>>> print(brown.words(categories='news'))
['The', 'Fulton', 'County', 'Grand', 'Jury', 'said', ...]
#PlaintextCorpusReader类
#官方文档:nltk.corpus.reader.plaintext.PlaintextCorpusReader
#介绍:基于文件系统,用来加载纯文本的类
>>> words = gutenberg.words('shakespeare-macbeth.txt')
>>> print(words)
['[', 'The', 'Tragedie', 'of', 'Macbeth', 'by', ...]
#标点符号也会被单独分出来
#断句,定义:sents(fileids=None)
>>> print(sents)
[['[', 'The', 'Tragedie', 'of', 'Macbeth', 'by', 'William', 'Shakespeare',
'1603', ']'], ['Actus', 'Primus', '.'], ...]
#分段,定义:paras(fileids=None)
paras = gutenberg.paras('shakespeare-macbeth.txt')
print (' '.join(paras[0][0]) #first para, first sentence)
[ The Tragedie of Macbeth by William Shakespeare 1603 ]           

NLTK数据挖掘工具的其他文本挖掘功能就不一一介绍了,在实践中常用的还有:

· 创建:定义__init__(self, tokens, name=None)。

· 查找单词:定义concordance(word, width=79, lines=25)。

· 搭配词:定义collocations(num=20, window_size=2)。

· 相似词:定义similar(word, num=20)。

· 相同上下文:定义common_contexts(words, num=20)。

· 词分布:定义dispersion_plot(words)。

· 正则表达式匹配单词:定义findall(regexp)。

· 词出现次数:定义count(word)。

· 词索引:定义index(word)。

· 文本总长度:len(text)。

· 生成FreqDist类:dist = text.vocab()。

· 打印频率分布图:定义plot(*args)。