情感分析在NLP领域中是应用很广泛的技术,一般用深度学习来解决这一类的问题。其实我的理解就是情感分析就是一个分类问题。这里我爬取了京东小米9的用户评论,正面和负面的评价各1000条,爬虫和整体的代码我放在了 GitHub 。然后我把预训练的词向量文件放在了 百度网盘,提取码:rxci。
我们一起来看看数据长得啥样,首先是小米9正面的评价:
然后是小米9负面的评价:
从这些数据印证了一句话,幸福的人都是相似的,不幸的人各有各的不幸。可以看到正类的评价里面基本上都是说小米9外观好看性能好,很容易就找到正类的特征词了。但是我们来看负类的小米9评价,基本上每一条负面评价吐槽的点都不一样,有对客服不满意的,有对小米活动失望的,有对没有优惠不满意的。有的正常看来似乎没有什么不满意,但是还是打了低分。这样的数据我感觉其实对结果是有一定影响的,我们如果想得到效果更好的模型,我们其实可以对数据进行筛选。好了,为了方便,我就直接用这个数据进行训练了。
首先我们逐行读取数据集,分别读取话术和标签。然后读入已经训练好的词向量 sgns.zhihu.bigram,这个训练好的词向量是一个长度为300维的。如下图所示,比如深圳这个词的300维词向量:
然后同时可以计算两个词的相似度:
同时也可以找出某一个词的最相似的 n 个词:
从上面的图可以看出,这个词向量训练的是不错的,和烤肉相似的都是一些吃的。然后我们可以用训练集构建词典,代码如下所示:
train_tokens = []
for text in train_texts_orig:# 去掉标点text = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "",text)# 结巴分词cut = jieba.cut(text)# 结巴分词的输出结果为一个生成器# 把生成器转换为listcut_list = [ i for i in cut ]for i, word in enumerate(cut_list):try:# 将词转换为索引indexcut_list[i] = cn_model.vocab[word].indexexcept KeyError:# 如果词不在字典中,则输出0cut_list[i] = 0train_tokens.append(cut_list)
这里我们定义一下输入token的长度:
我们长度定98就可以覆盖了95%以上的话术长度了。然后不足98的我们在前面补0:
然后我们处理好训练集之后,我们可以开始定义网络了,这里我们用双向LSTM加一个输出层,网络结构非常简单,代码如下所示:
model = Sequential()
model.add(Embedding(num_words,embedding_dim,weights=[embedding_matrix],input_length = max_tokens,trainable = False))
model.add(Bidirectional(LSTM(units=64, return_sequences=True)))
model.add(LSTM(units=16, return_sequences=False))
model.add(Dense(1, activation='sigmoid'))
# 我们使用adam以0.001的learning rate进行优化
optimizer = Adam(lr=1e-3)
代码结果如下所示:
然后我们就可以进行模型训练了,训练完成之后,我们需要一个预测的函数:
def predict_sentiment(text):print(text)# 去标点text = re.sub("[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+", "",text)# 分词cut = jieba.cut(text)cut_list = [ i for i in cut ]# tokenizefor i, word in enumerate(cut_list):try:cut_list[i] = cn_model.vocab[word].indexif cut_list[i] >= 30000:cut_list[i] = 0except KeyError:cut_list[i] = 0# paddingtokens_pad = pad_sequences([cut_list], maxlen=max_tokens,padding='pre', truncating='pre')# 预测result = model.predict(x=tokens_pad)coef = result[0][0]if coef >= 0.5:print('是一例正面评价','output=%.2f'%coef)else:print('是一例负面评价','output=%.2f'%coef)
这也是讲输入的话术去掉符号之后分词,然后向量化之后进行预测,我们可以看看预测的结果:
总的来说分类效果还是不错的。这就是用双向LSTM进行情感分析的整个流程,希望可以帮助大家理解整个的中文情感分析流程和原理,谢谢。