一、实验目的及任务
1.1 实验目的
- 了解NLP的基本知识
- 了解gensim库的使用
- 学习Word2Vec算法实战
- 学习文本预处理等相关内容
二、实验环境
- Ubuntu1604 系统;
- 用户账号:stu/stu123;管理员:root/root123
三、实验步骤
3.1 认识NLP
你使用过苹果公司的人工智能语音助手Siri吗?有没有好奇过Siri是如何理解你说的(大部分的)话?Siri的工作过程就是自然语言处理在实践中应用的一个鲜活案例。
自然语言处理(NLP)是一种专业分析人类语言的人工智能。(简称为NLP
),它的工作原理是这样的:
- 接收自然语言,这种语言是通过人类的自然使用演变而来的,我们每天都用它来交流
- 转译自然语言,通常是通过基于概率的算法
- 分析自然语言并输出结果
3.2 NLP 技术解析 – 词向量
从上我们大概知道的整体的运作流程,但还是相当匪夷所思。计算机怎么能读懂我们说的话呢?
毕竟我们对着电脑喊,它也不知道我在干什么。
计算机的世界里只有0
和1
。
那么问题来了,如何转换成计算机所熟知的内容。就需要用到我们数学中的大杀器:词向量。
如果数学知识了解不多可按需复习,不需要了解全部的知识才来学习。
例如我们有两句话,并假设转换成词向量:
【我想要吃苹果】
举例:[ 10, 20, 30, 40, 50, 60 ] 设向量为a
【我想要苹果吃】
举例:[ 10, 20, 30, 50, 60, 40 ] 设向量为b
那么从上面a
,b
两个向量我们就可以觉得这两句话是一个意思。
3.3 NLP 技术解析 – 分词
我们理解计算机用什么方式能够理解我们说的话,现在又遇到了一个问题:
如何把我们重要的文字转换成词向量
这是迫在眉睫的需要解决的问题,我们采取分词的方式进行解决。
例如:【我想要吃苹果!】
对于如上这一句话我们可以分成:【 我 / 想要 / 吃 / 苹果 / ! 】
在上述内容当中,就分成了【我】,【想要】,【吃】,【苹果】,【!】等这几个词,很容易观察到其实有些内容我们是并不需要等。例如感叹号,那么我们就对她进行删除,诸如此类的还有很多的地嗯啊,。...
等等的停用词
我们讲他去除,这样也减少我们向量运算的维度和影响。
在这里我们进行了两个内容:
- 分词
- 去停用词
我们也可以考虑加入低频词,出现频率低的词进行删除
3.4 Word2Vec
Word2vec 论文由 Google 的研究团队发布于 2013 年,它的发布,很大程度上改变了 NLP 技术的发展,不仅如此,在使用神经网络来解决各个领域的问题时,谈必离不开 Embedding,而 Embedding 究竟是什么?了解 Word2vec 的同学都知道,它其实是 Word2vec 的另一个名字,或广义的 Word2vec,是一种使用稠密向量来表示特征的表示学习方法。
例如在搜索与推荐领域,Word2vec 的思想可以用来对 Item、Query 和 User 等关键特征编码,产生 Item、Query 和 User 的稠密向量,有了这些向量后,就可以进一步将它们用于召回和排序场景中。可以毫不夸张的说,它是智能化搜索和推荐系统的基础,或者说 Word2vec 的出现,推进了搜索与推荐领域智能化的发展。
例如:
隔壁 张阿姨 觉得 刘德华 很 帅
隔壁 张阿姨 觉得 我 很 帅
复制代码
例如过后两者的稠密向量
刘德华[0.9, 0.3]
我 [0.89999, 0.3]
复制代码
那么我
= 刘德华
。说明两个词是相近的。
Word2Vec的处理有两种模型:CBOW 模型
和Skip-gram 模型
这里不再展开。同学们可以参阅其他论文进行学习。
3.5 Anaconda3 安装
- 下载Anaconda;
$ cd ~/Downloads # 进入下载目录
$ wget 去官网下载哦哈哈哈哈 #下载资源
$ sudo sh ./Anaconda3-2019.07-Linux-x86_64.sh
复制代码
按回车继续;
然后按住回车阅读注册信息,然后输入yes
。
查看文件即将安装的位置,按回车,即可安装;
输入yes
,初始化conda;
至此Anaconda安装完成
安装完成后关闭终端,重新打开即可。
3.6 Gensim 安装
Gensim是一款开源的第三方Python工具包,用于从原始的非结构化的文本中,无监督地学习到文本隐层的主题向量表达。
它支持包括TF-IDF,LSA,LDA,和word2vec在内的多种主题模型算法,
支持流式训练,并提供了诸如相似度计算,信息检索等一些常用任务的API接口等。
他的安装也是非常简单。
pip install gensim
复制代码
如果其中使用提示numpy某些属性或者函数不可用,需升级numpy版本。
pip install numpy=1.19.2
3.7 Jieba 分词安装
jieba分词是用于中文分词非常好用的一款工具包,安装也非常简单
pip install jieba
复制代码
四、实验步骤
我们从某市的市民服务中心获取服务问答情况,分析题目而获取最类似的问答内容。
数据内容如上,因问题或者回答不可控因素,数据分隔符采用++$++
。
问答数据集:
$ cd ~/Downloads # 进入下载目录
$ wget -c http://res.aihyzh.com/基于政务领域的智能问答/data.txt #下载资源
复制代码
停用词数据集:
$ cd ~/Downloads # 进入下载目录
$ wget -c http://res.aihyzh.com/基于政务领域的智能问答/stop_words.txt #下载资源
复制代码
我们在终端输入
jupyter notebook
复制代码
打开我们的编辑器,新建一个Python3
文件,进行我们以下的实验内容
4.1 加载数据内容
首先我们先加载相关包
import pandas as pd
import jieba
from gensim.models import word2vec
复制代码
没有任何的报错提示,即正确。如有其他错误可结合搜索引擎进行解决。
我们通过文本加载数据并用++$++
作为分隔符:
q = [] #问题列表
a = [] #答案列表
# 读取数据文件的内容
with open('/home/stu/Downloads/data.txt') as f:
# 以行模式读取内容放到text中,
text = f.read().splitlines()
for line in text:
# 分隔符每行的数据,返回qa列表
qa = line.split("++$++")
try:
# 第一列为问题,第二列为答案
q.append(qa[0])
a.append(qa[1])
except:
# 如果遇到了错误的,打印出来。进行格式调整
print("error", qa, index)
qa_table = pd.DataFrame({ 'q':q, 'a': a })
qa_table
复制代码
我们可以打印qa_table
查看我们的数据内容是否成功加载
4.2 创建停用词表
停用词文件在上面也已经下载了,
内容格式是一行一个内容,那么我们直接将数据进行加载。
# 停用词表
stop_words = []
with open('/home/stu/Downloads/stop_words.txt') as f:
stop_words = f.read().splitlines()
# stop_words
复制代码
4.3 创建分词函数
我们通过jieba分词,并通过停用表进行过滤一些多余的数据
def get_words_by_jieba(line, stop_words):
# 通过jieba.cut进行分词
words = list(jieba.cut(line))
# 将分词数据进行循环,去除停用词
for w in words:
print("w", w, w in stop_words)
if w in stop_words or w.strip() == "" :
words.remove(w)
return words
# 测试一下
get_words_by_jieba("古北路拓宽工 程施工噪音扰民严重超标。", stop_words)
复制代码
4.4 获取所有分词
在这一步我们将所有的问题进行循环,并且将题目进行分词,分词后的数据放到字典中。构建一个数据格式:{"噪音": [1, 3, 10]}
这样说明噪音
这个词出现在第1,3,10问题,那么判断这几个题目哪个相似度比较高一点。
qa_index_dist = {} # 所有的分词对应哪个编号,Key 词汇, Value是索引
qa_all_words = [] # 所有的分词
# 迭代qa_table所有数据
for row in qa_table.iterrows():
# 第一个是 索引,第二个第一列也就是q,第三个是第二列也就是a
qa_index = row[0]
# 分词并去停用词
question_cut = get_words_by_jieba(row[1]["q"], stop_words)
# 加入到分词组中
qa_all_words.append(question_cut)
for word in question_cut:
if word in qa_index_dist:
# 如果单词在列表中,更新索引
qa_index_dist[word].add(qa_index)
else:
qa_index_dist[word] = set()
qa_index_dist[word].add(qa_index)
# 如果单词不再列表中,加入
复制代码
两个内容的具体数据格式 ⬇️⬇️⬇️
4.5 训练模型
训练模型非常简单,我们刚刚通过gensim包加载了Word2Vec。
# 训练模型
model = word2vec.Word2Vec(qa_all_words, min_count=1)
# 第一个参数是句子,可以是列表,也可以是通过word2vec.LineSentence加载的数据等
# min_count 是最小词频过滤
复制代码
更多参数可参考:
https://radimrehurek.com/gensim/models/word2vec.html
4.6 定义最相似问题函数
首先我们从这个函数的作用进行分析,用户输入问题,我们获取最相似的几个问题进行返回。那么它会分成三步:
- 将输入问题进行分词并过滤停用词
- 根据词汇获取相关索引编号
- 根据索引编号找到问题,匹配问题库中问题与用户输入的相似度
# 第一个参数是输入问题
# 第二个停用词列表
# 第三个参数原题库表
# 第四个参数是模型
def get_similarity_qa(input_question, stop_words_list, qa_table, model):
# 对输入的问题进行分词
input_words = get_words_by_jieba(input_question, stop_words_list)
# 循环输入问题的分词,判断一下这个分词我们是否有,如果没有我们就删除
# 模型匹配不能有不存在的分词,会导致出错
for w in input_words:
if w not in qa_index_dist.keys():
input_words.remove(w)
# 根据剩余的分词获取这些分词对应的题库索引,
# 通过set的update操作可以将所有相关的索引都放到一个set中,并且去除重复的
input_words_index = set()
for words in input_words:
input_words_index.update(qa_index_dist[words])
# 定义相关问题列表
siml_list = []
# 循环所有相关索引的题目
for index in input_words_index:
# 「题库中的题目」与「输入问题的分词」进行相似度匹配
# 加入到问题列表中
# simi 相似度
# words 问题原本名称
simi = model.wv.n_similarity(qa_all_words[index], input_words)
words = qa_table["q"][index]
siml_list.append([simi, words])
# 返回根据simi正向排序的内容
return pd.DataFrame(siml_list,columns=['simi','words']).sort_values(["simi"], ascending=False)
复制代码
效果还是不错看起来比较好的。
看完点个赞吧~ ?