1 初始文本挖掘
1.1 何为文本挖掘
文本挖掘是指从大量文本数据中抽取事先未知的、可理解的、最终可用的知识的过程,同时运用这些知识更好地组织信息以便将来参考。
1.2 文本挖掘基本流程
文本挖掘的过程相似于又区别于数据挖掘。
参考: 用 Python 做文本挖掘的流程
1.3 文本挖掘的应用
- 基于内容的推荐,例如基于小说内容相似度的小说的推荐
- 信息自动分类
- 信息自动抽取
- 自动问答、机器翻译
- …….
2 Python的jieba模块使用基础
“结巴”中文分词:做最好的Python 中文分词组件
2.1 安装(windows)
2.1.1 安装步骤
- 打开cmd
- 输入:pip install jieba,完成模块安装
- 在python环境:import jieba
2.1.2 文件结构与解析(部分)
我们可以注意到有一个dict.txt文件,这就是jieba模块的基础字典,也是其分词的基础,打开字典后有如下图三列,分别表示词语、词频与词性:
其中对于词性的对照具体参考:结巴分词标注兼容_ICTCLAS2008汉语词性标注集
2.2 分词
2.2.1 分词模式
在jieba分词中支持三种分词模式(默认为精准模式):
- 精确模式:试图将句子最精确地切开,适合文本分析;
- 全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
- 搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
实例
import jieba
testSentence = "利用python进行数据分析"
print("1.精准模式分词结果:"+"/".join(jieba.cut(testSentence,cut_all=False)))
print("2.全模式分词结果:"+"/".join(jieba.cut(testSentence,cut_all=True)))
print("3.搜索引擎模式分词结果:"+"/".join(jieba.cut_for_search(testSentence)))
print("4.默认(精准模式)分词结果:"+"/".join(jieba.cut(testSentence)))
结果
1.精准模式分词结果:利用/python/进行/数据分析
2.全模式分词结果:利用/python/进行/行数/数据/数据分析/分析
3.搜索引擎模式分词结果:利用/python/进行/数据/分析/数据分析
4.默认(精准模式)分词结果:利用/python/进行/数据分析
2.2.2 查看词性
实例
import jieba.posseg
testSentence = "利用python进行数据分析"
words = jieba.posseg.cut(testSentence)
for item in words:
print(item.word+"----"+item.flag)
结果
利用----n
python----eng
进行----v
数据分析----l
2.3 添加自定义词典
2.3.1 词典加载
在分词过程中我们会遇到一些jieba自带的词典中没有的词,比如随意构造“书院”
import jieba
#词典加载
testSentence2="书院是一个很好的交流平台"
print("+---------+---------+---------+---------+---------+---------+---------+----")
print("1.加载词典前分词结果:")
print([item for item in jieba.posseg.cut(testSentence2)])
print("+---------+---------+---------+---------+---------+---------+---------+----")
jieba.load_userdict("C:/Anaconda3/Lib/site-packages/jieba/dict2.txt")
print("2.加载词典后分词结果:")
print([item for item in jieba.posseg.cut(testSentence2)])
结果如下:
+---------+---------+---------+---------+---------+---------+---------+----
1.加载词典前分词结果:
[pair('', 'n'), pair('书院', 'n'), pair('是', 'v'), pair('一个', 'm'), pair('很好', 'a'), pair('的', 'uj'), pair('交流平台', 'n')]
+---------+---------+---------+---------+---------+---------+---------+----
2.加载词典后分词结果:
[pair('书院', 'x'), pair('是', 'v'), pair('一个', 'm'), pair('很好', 'a'), pair('的', 'uj'), pair('交流平台', 'n')]
我们可以注意到书院在加载自建字典够能够被精准地分出来。
在添加字典注意将txt文档保存为utf-8编码,如下图示:
2.3.2 调整词典
- 只能调高词频,不能调低词频
add_word(word, freq=None, tag=None)
suggest_freq(segment, tune=True) - 只能降低词频,不能调高词频
�del_word(word)
suggest_freq(("segmentPart1","segmentPart2"),True)
(1)调高词频
实例
import jieba
print("1.原始分词结果:"+"/".join(jieba.cut("数据分析与数据挖掘的应用", HMM=False)))
jieba.add_word("的应用")
print("2.使用add_word(word, freq=None, tag=None)结果:"+"/".join(jieba.cut("数据分析与数据挖掘的应用", HMM=False)))
jieba.suggest_freq("的应用",tune=True)
print("3.使用suggest_freq(segment, tune=True)结果:"+"/".join(jieba.cut("数据分析与数据挖掘的应用", HMM=False)))
结果
1.原始分词结果:数据分析/与/数据挖掘/的/应用
2.使用add_word(word, freq=None, tag=None)结果:数据分析/与/数据挖掘/的应用
3.使用suggest_freq(segment, tune=True)结果:数据分析/与/数据挖掘/的应用
(2)降低词频
实例
import jieba
jieba.suggest_freq(("中","将"),True)
print("使用suggest_freq(('segmentPart1','segmentPart2'),True)分词结果:"+"/".join(jieba.cut("在中将尽力呈现优质内容", HMM=False)))
结果
使用suggest_freq(('segmentPart1','segmentPart2'),True)分词结果:在/简/书/中/将/尽力/呈现/优质/内容
2.4分词分析
进一步我们需要对文本信息进行相关分析,如返回词语所在位置、返回关键词等等。
2.4.1 返回词语所在位置
实例
import jieba.analyse
print("1.采取精准模式结果:")
print([item for item in jieba.tokenize("数据分析与数据挖掘的应用")])
print("-------------------")
print("2.采取搜索模式结果:")
print([item for item in jieba.tokenize("数据分析与数据挖掘的应用",mode="search")])
结果
1.采取精准模式结果:
[('数据分析', 0, 4), ('与', 4, 5), ('数据挖掘', 5, 9), ('的', 9, 10), ('应用', 10, 12)]
-------------------
2.采取搜索模式结果:
[('数据', 0, 2), ('分析', 2, 4), ('数据分析', 0, 4), ('与', 4, 5), ('数据', 5, 7), ('挖掘', 7, 9), ('数据挖掘', 5, 9), ('的', 9, 10), ('应用', 10, 12)]
返回的数据格式为:[('词语',开始位置,结束位置),...,()]
2.4.2 提取文本中的关键词
实例
import jieba.analyse
print(jieba.analyse.extract_tags("我喜欢广州小蛮腰",3))
print(jieba.analyse.extract_tags("我喜欢广州广州小蛮腰",3))
print(jieba.analyse.extract_tags("我喜欢广州广州广州小蛮腰",3))
结果
['小蛮', '广州', '喜欢']
['小蛮', '广州', '喜欢']
['广州', '小蛮', '喜欢']
其结果是结合文中出现的词频与字典中的词频进行排序。
3 文本相似度
在许多app中都有推荐功能,比如网易云音乐有每日歌曲推荐、某些阅读软件有书籍阅读等等,一般的推荐模式有基于用户和基于内容,其中基于内容的推荐可能就有计算到文本相似度,当然肯定还结合了其他维度,如音乐的风格等。同理在搜索引擎中也会根据与搜索关键词的相似度对网页进行排序。接下来将实现基于TF-IDF加权技术的文本相似度计算。
3.1 理论概念
语料库:真实存在的语言材料
稀疏向量与稀疏矩阵
稀疏向量就是包含较多0值的向量,正常的向量可以拆分成值向量和顺序向量,如稀疏向量(2,0,3,4,0,5,0,6)可用值向量(2,3,4,5,6)和顺序向量(1,0,1,1,0,1,0,1)表示。
同理稀疏矩阵也类似,只不过稀疏矩阵可将元素转换为三元组表,如矩阵[2 0 0 0;0 5 0 6]的三元组表为[2 1 1;5 2 2;6 2 4],其中第一个三元组表示矩阵中的元素2是在矩阵的第1行第1列的位置。TF-IDF:是一种用于资讯检索与资讯探勘的常用加权技术。
(1)TF(term frequency)
词频,指的是某一个给定的词语在该文档中出现的频率。计算公式为某词在一个文档中出现的次数除以所有字词在该文档中出现的次数。
其中以所有字词在文档中出现的系数作为分母目的在于将词数进行归一化是为了防止偏向长的文档(不管该词语重要与否,同一个词语在长文档里可能会比短文件有更高的词数)。
(2)IDF(inverse document frequency)
逆向文件频率,是一个词语普遍重要性的度量。计算公式为总文档数目除以包含该词语之文件的数目,再将得到的商取对数。
(3)计算实例
词语“母牛”在某一篇总词语数为100个的文件出现了3次,该文件所在的语料库的文件总数为10,000,000份,并且“母牛”在其中的1,000份文件出现过,那么“母牛”一词在该文件中的词频就是3/100=0.03,其逆向文件频率为 log(10,000,000 / 1,000)=4。最后的TF-IDF的分数为0.03 * 4=0.12。
参考:TF-IDF及其算法
3.2 计算步骤
- 文档读取
- 文档分词
- 文档格式归一化
- 统计词频,词语过滤【可选】
- 通过语料库建立词典,并通过token2id获取特征数提取词典特征数
- 基于词典建立新的语料库
- 将新语料库通过TF-IDF进行处理
- 读取要对比的文档,并将格式归一化
- 将对比文档转化为稀疏向量
- 计算稀疏矩阵相似度,从而建立索引
- 打印输出最终相似度
3.2 实战
3.2.1 需求
假设我们有一个搜索引擎资源库,里面包含sentence1,sentence2,sentence3三个句子,现在我们将要进行查询并按相似度进行排序返回结果。
3.2.2 Python实现
'''
利用gensim做TF-IDF主题模型
'''
from gensim import corpora, models, similarities
import jieba
from collections import defaultdict
# 1.导入句子
sentence1 = "我喜欢吃番薯"
sentence2 = "番薯是个好东西"
sentence3 = "利用python进行文本挖掘"
# 2.分词
data1 = " ".join(jieba.cut(sentence1))
data2 = " ".join(jieba.cut(sentence2))
data3 = " ".join(jieba.cut(sentence3))
# 3.转换格式:"词语1 词语2 词语3 … 词语n"
texts = [list(data1), list(data2), list(data3)]
# 4.基于文本建立词典
dictionary = corpora.Dictionary(texts)
featureNum=len(dictionary.token2id.keys())#提取词典特征数
dictionary.save("./dictionary.txt")#保存语料库
# 5.基于词典建立新的语料库
corpus = [dictionary.doc2bow(text) for text in texts]
# 6.TF-IDF处理
tfidf = models.TfidfModel(corpus)
'''
# 输出每个句子每个词语的tfidf值
corpus_tfidf = tfidf[corpus]
for doc in corpus_tfidf:
print(doc)
'''
# 7.加载对比句子并整理其格式
query = "吃东西"
data4 = jieba.cut(query)
data41 = ""
for item in data4:
data41 += item+" "
new_doc = data41
# 8.将对比句子转换为稀疏向量
new_vec = dictionary.doc2bow(new_doc.split())
# 9.计算相似性
index = similarities.SparseMatrixSimilarity(tfidf[corpus],num_features=featureNum)
sim = index[tfidf[new_vec]]
for i in range(len(sim)):
print("查询与第"+str(i+1)+"句话的相似度为:"+str(sim[i]))
注意:
官方文档中提示建立的语料库是存在内存中的一个列表格式,因此对于很大的语料库,最好还是存在硬盘上,然后依次访问文件。这样可以不用考虑语料库的大小,也避免了占用太多内存。
3.2.3 结果与分析
最终输出结果如下:
查询与第1句话的相似度为:0.399284
查询与第2句话的相似度为:0.347683
查询与第3句话的相似度为:0.0
我们可以看出查询的句子“吃东西”与第一句话“我喜欢吃番薯”相似度最高,其次是第二句话“番薯是个好东西”,最后是第三句话,很明显第一句话和第二句中的番薯是一种食物,故跟查询的关键词“吃东西”有相关,但是第三句话完全跟吃东西没关,故返回的相似度为0,至于与第一句话的相似度为什么比第二句话高,这就需要考虑句子中具体的词或词语的TF-IDF值和余弦相似度了。
综上,最终我们查询返回的顺序应如下:
(1)我喜欢吃番薯
(2)番薯是个好东西
(3)利用python进行文本挖掘
4 后记
实际上Python中的gensim模块还提供了SVD、LDA等主题模型,有兴趣的读者可以继续研究,另外对于文本挖掘有兴趣的小伙伴可以参考[我爱自然语言处理]。(http://www.52nlp.cn/)
本文所有代码只用于技术交流,拒绝任何商用活动
个人Github
后续的学习细节将会记录在个人博客DebugNLP
中,欢迎各路同学互相交流