自从18年10月底开始课余在导师的公司实习,不知不觉入坑机器学习和深度学习已经小半年时间。目前的主要方向是NLP和数据挖掘。
这期间接触了许多新的知识,见识了火热的深度学习的魅力和实际应用,也认识了很多浙大的牛人,有很多感触。
这篇文章,是对我近期做的情感分析demo的一个总结;但正因为它简单又内容丰富,相信会帮助即便外行的读者,也能对爬虫和深度学习有新的认识。
全文共计3800余字,阅读时间预计10分钟。阅读完本文,你将学习到:
01 如何安装使用python
02 如何用python爬取数据
03 如何使用pandas、numpy做简单的数据处理
04 如何调用bert-as-service,快速得到中文词向量
05 如何使用深度学习框架keras建模,做简单的情感分析
01 如何安装使用Python
安装python
的方式很多,而Mac os
和Ubuntu
等操作系统甚至已经预装了python
。
但是,我还是强烈推荐你安装Anaconda
套装。它是一个开源的python发行版本,包含了180多个科学包及其依赖项,其中很多工具包对于后期机器学习的研究非常重要。所以第一次就安装它,可以“一劳永逸”。
进入Anaconda
官网的下载页面,可以根据你使用的系统下载最新版本的conda
。如果你想下载历史版本的Anaconda
,可以点击此链接
此后,根据中文提示一步步安装即可,非常简单方便。
Windows
下称“命令提示符”),我们使用conda
创建一个虚拟环境,这样可以和系统中原有的python环境相隔离。
如图,我们创建了一个python3.6
版本的虚拟环境,使用conda env list
可以查看我们当前所有虚拟环境(目前只有py36),然后source activate py36
激活它。
到此,python
最基础的环境搭建全部完成啦。
02 如何用python爬取数据
学不学计算机,想必你都曾经听过“爬虫”这个词。说实话,我当初第一次听到这两个字,想到的是一群虫子在我身上爬,起了一身鸡皮疙瘩....
好!我们言归正传。在准备爬取数据前,我们得先对什么是爬虫有简单的了解:
网络爬虫(Web crawler),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,采集所有其能够访问到的页面内容(包括文本、图片、视频、音频等)
简单的说,所谓爬虫就是用程序去自动采(爬)集(取)互联网上的公开内容。
而爬虫之所以总是和python
挂钩,是因为python
这一脚本语言非常适合写爬虫代码。如果你问我有多简单?
两行代码就完事了!
import requests
r = requests.get(url="http://www.baidu.com")
requests
库会自动向我们指定的url链接(百度)发起http请求,并将结果返回到r.content
中。
当然这只是最简单的一种情况,爬取到的内容也不过是百度首页的源码;但实际开发爬虫时的核心内容,已经在这两行代码里完美呈现了,可以说剩下的都是“点缀”。
在我们的这个项目中,使用了一个比requests库稍复杂的框架Scrapy
,它是python
最火热的爬虫框架,结构化的设计可以让开发人员非常方便的根据项目需求进行修改。
如果对 Scrapy
有兴趣的同学,我可以为你提供一些参考资料:
01 Scrapy官方文档
02 《Python爬虫开发与项目实战》
03 构建单机千万级别的微博爬虫系统
当然,我觉得最快的学习方式是先简单了解scrapy
的理论基础(如5大组成部分),然后进行项目实战(参考微博爬虫项目,写的挺完善)。
这里的美团点评爬虫,爬取的是杭州、上海、北京等5大城市各1000家餐馆的前200条点评(合计约100w+评论数据),通过构造访问api
接口,提取json
格式的数据。代码类似于长这样:
由于本文的重点不是爬虫讲解,所以代码部分直接一带而过。
在评论内容的筛选上,我只保留了4-5星和1-2星的评论,作为后期情感识别的训练/测试数据。
最终爬取结果:
mongodb
中,省去了建表的麻烦。
如果嫌慢,我们还可以采取分布式的架构(如scrapy-redis
),加快爬虫的爬取速度。
耐心等待爬虫运行结束,去数据库中查看爬虫忠诚的为我们爬取的数据:
有了数据,接下来要做的就是数据预处理啦!
03 使用pandas、numpy做简单的数据处理
很多人把pandas
、numpy
、matplotlib
3个库称为python数据处理和可视化的三剑客,因为它们真的功能强大又好用。这里我先介绍前两个,matplotlib
留到第5小节。
我们爬取的数据保留在mongodb
中,我们可以用mogoexport
或借助数据库可视化软件将其导出到csv
文件中。
这里为了简化,我们分别导出评分5星和评分1星的评论(刚好对应正负两面情感)各6800条;在后续处理中,每种情感取6000条用作训练(包含验证集),剩余800条作为测试。
我们分别导出的数据命名为10_star.csv
、50_star.csv
,借助pandas
库用一行代码导入,并查看前5行内容。
import pandas as pd
df1 = pd.read_csv('./10_star.csv')
df2 = pd.read_csv('./10_star.csv')
print(df1.head())
print(df1.head())
接下来,我们要遍历comment
列的每一行,过滤其中的非中文字符;再将字数大于10的评论加入一个列表。
这是对其中的负面评论的数据处理,正面评论处理类似。最后将数据直接整合在一起:
X_data = X_data1[:6000] + X_data2[:6000] # 训练数据
X_test_data = X_data1[6000:6800] + X_data2[6000:6800] # 测试数据
请注意,这里我们保证了X_data
前6000条数据是负面的(来自X_data1),后6000条是正面的(来自X_data2)。X_test_data
也同理。
得到训练数据后,我们手工创建一个labels
数组(训练标签),前6000个元素是0,后6000个元素是1;再通过numpy
库转换为numpy数组
,便于后期输入到神经网络中。
import numpy as np
y_data = [0 for i in range(6000)] + [1 for i in range(6000)]
y_data = np.asarray(y_data, dtype=np.float32)
y_test_data = [0 for i in range(800)] + [1 for i in range(800)]
y_test_data = np.asarray(y_data, dtype=np.float32)
现在,聪明的你可能发现一个问题:我们的数据太有规律啦,正负情感刚好前后各占了一半;假如我们输入了前3000条到模型中,机器“机智的”全判断为负面,能证明准确率就有100%了?
为了避免数据分布不规律的现象,我们需要为数据进行“洗牌”(随机打乱)。
还是借助numpy
,我们可以轻松实现这一过程。
X_train = []
y_train = []
X_test = []
y_test = []
nums = np.arange(12000)
# 随机打乱12000个训练数据
np.random.shuffle(nums)
for i in nums:
X_train.append(X_data[i])
y_train.append(y_data[i])
# 随机打乱1600个测试数据
nums_ = np.arange(1600)
np.random.shuffle(nums_) # shuffle改变的是自身的内容
for i in nums_:
X_test.append(X_test_data [i])
y_test.append(y_test_data [i])
# list转Numpy数组
X_train= np.asarray(X_train, dtype=np.float32)
X_test= np.array(X_test, dtype=np.float32)
到此为止,简单的数据预处理就结束了,是不是可以开始搭建我们的神经网络模型了?
别急!这儿我们的数据还全都是中文,即便是英文字母,计算机也一概不认识。所以,一位重量级的选手马上就要登场和我们见面了。👏👏
04 调用bert-as-service,快速得到中文词向量
在自然语言处理任务中,首先需要考虑词如何在计算机中表示。常见的表示方法有两种
01 one-hot representation (独热编码)
02 distribution representation
第一种是离散的表示方法,得到的是高维度的稀疏矩阵;第二种方法(Word Embedding)则是将词表示成定长的连续稠密向量。想深入的同学,请利用好您的搜索引擎(上网搜!)
从头训练一个有效的语言模型是耗时又耗能的过程。学习NLP的同学,一定知道去年底Google发布的Bert
模型。
本例中,我们借助腾讯AI实验室发布的bert-as-service
接口,让你能简单的通过两行代码,即可使用预训练好的bert模型生成句向量和ELMO风格的词向量。
关于bert-as-service
的官方介绍,可以点击查看作者:肖涵博士的Git仓库。
我们来看一看这两行代码是怎么实现的?
from bert_serving.client import BertClient
bc = BertClient
# 将待训练的中文数据转换为(,768)维的句向量
input_train = bc.encode(X_train)
觉得上面的内容不能马上看懂?
没关系,送上免费学习传送门:两行代码玩转Google BERT句向量词向量。写的很详细哦!
bert-as-service
将一个句子统一转换成768维
的句向量;最终我们得到的就是12000 * 768
维度的句向量矩阵,也就是我们将输入到神经网络模型的真正数据。
05 使用Keras,实现简单的情感分析模型
虽然我们这里跑的只是一个很小的demo,但是数据处理部分依然是整个工程中最耗时间的部分;实际开发中也往往如此。
有了处理后的数据,后边的路一下畅通了许多,尤其是有keras
这样容易上手的工具。
Keras
是一个高层神经网络API,由纯python
编写并使用Tensorflow
,Theano
,CNTK
作为后端,以简介、快速为设计原则。
直接使用pip
即可快速安装Keras
和Tensorflow
$ pip install keras
$ pip install tensorflow
典型的Keras
工作流程大致可以分为四步:
(1) 定义训练数据:输入张量和目标张量。
(2) 定义层组成的网络(或模型),将输入映射到目标。
(3) 配置学习过程:选择损失函数、优化器和需要监控的指标。
(4) 调用模型的 fit 方法在训练数据上进行迭代
我们直接使用使用Sequential
类来定义模型(仅用于层的线性堆叠,是最常见的网络架构)。
from keras.models import Sequential
from keras.layers import Dense, Dropout
import tensorflow as tf
model = Sequential()
# 搭建模型
model.add(Dense(32, activation='relu', input_shape=(768,)))
model.add(Dropout(0.3))
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
对于简单的二分类问题,模型使用Dense
全连接层拼接已经够用,最后的输出就是一个数,代表了正面/负面情感的概率。同时防止过拟合,在模型中加入了Dropout
层,
接下来,我们来指定模型使用的优化器和损失函数,以及训练过程中想要监控的指标。
model.compile(
loss='binary_crossentropy',
optimizer=tf.train.AdamOptimizer(),
metrics=['acc']
)
最后,通过fit
方法将输入数据的Numpy数组
传入模型;请注意,我们留出了20%的数据作为验证集:
history = model.fit(
X_train, y_train,
epochs=30,
batch_size=128,
validation_split=0.2,
verbose=1
)
我们的模型就开始愉快的迭代训练啦!
可以观察到,随着迭代次数增加,模型的损失
loss
逐渐下降,准确度acc
逐渐上升,直到最终趋于稳定,与我们的预期完全一致。
运行结束后,我们使用matplotlib
库将结果可视化吧~
import matplotlib.pyplot as plt
history_dict = history.history
epochs = range(1, len(history_dict['acc']) + 1)
# 绘图部分
plt.figure()
plt.plot(epochs, history_dict['acc'], 'b', label='acc')
plt.plot(epochs, history_dict['val_acc'], 'bo', label='val_acc')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
分别画出训练过程中损失和精确度的变化,可以知道我们的模型确实从输入数据中有效“学习”到了情感识别的模式。
因为训练数据不算太少,又加入了
dropout
预防过拟合,同时任务本身不算复杂,保证了我们的模型对于美团点评数据是好评还是差评有了96%
的准确率!通过调参和加大模型的复杂度,这一结果应该会更高。
别忘了我们还有1600条
数据被当作测试集还没使用,也就是说模型还没有“见过”这批数据。是时候派他们上场了!
调用evaluate
方法实验我们的测试数据:
test_loss = model.evaluate(
X_test,
y_test,
batch_size=63,
verbose=1
)
print(test_loss)
得到结果:
[0.07956909381508012, 0.9731250016018749]
它表示训练损失和准确率分别为0.07
和97%
。
小结
本文带你了解了如何安装使用python
,如何使用python
爬取数据(构造爬虫),如何处理数据以及使用Keras
训练模型,让最后的结果可视化。
可能涉及的内容比较多,又限于篇幅,对各个模块的内容只是管中窥豹,简要带过。
其实,这里很多模块的内容远不是一篇文章,甚至一本书就能全面详细介绍的(如对于爬虫的反爬措施部分,就可以写一本书)。如果大家愿意看,笔者会持续更新本专题下的文章。对于本文谈论的内容,你有没有什么不同的意见或者更好的建议?欢迎留言!
喜欢请不要吝啬于点赞哈。