情感分析中机器学习和深度学习的运用
情感分析分成情感倾向分析和情感倾向程度分析。
情感倾向分析其实是一个分类问题,粗一点的话呢可以分两类,正面情感和负面情感。细一点的话呢,甚至可以分成喜怒哀乐等。
而情感倾向度分析,语言所表达的情感的强烈程度。
下面我将介绍几种方法来进行情感倾向分析。
进行情感分析最快或者说是最基本的方法是使用市面上成熟的工具包来进行分析,像snowNLP。或者使用神经网络,例如深度神经网络,或者循环神经网络的方式来处理,也是可以的
snowNLP
snowNLP的使用方式很简单:
from snownlp import sentiment
from snownlp import SnowNLP
#判断一句话的情感倾向
print(SnowNLP('我怎么这么好看').sentiments)
#模型训练
sentiment.train('neg.txt', 'pos.txt')
#模型保存
sentiment.save('sentiment.marshal')
#模型加载
sentiment.load('sentiment.marshal')
原理:
1. 使用贝叶斯的模型进行模型的建立和预测
2. 对输入的训练数据进行分词处理,再进行停词处理(去掉标点符号,代词,数次,专业名词);(概率分析的单元是对词,不是对句子)
3. 形成一个正面词字字典和一个负面词字典(key:词名,value:频率)
4. 训练的过程就是,不断分词,去停词,统计词频率的过程
5.利用朴素贝叶斯的思想进行预测的过程:
通过对词库的统计可以知道,正面词库的先验概率P(pos), 负面词库的先验概率P(neg)。假设当前要判断倾向的句子是x,它由词符[a,b,c]组成,那么P(pos|x) = P(pos,x)/P(x) = P(x|pos)*P(pos)/P(x)=P(a|pos)*P(b|pos)*P(c|pos)*P(pos)/P(a)*P(b)*P(c)
深度学习的做法
深度学习的做法主要思考两个问题:
1. 中文句子如何转化成向量,输入到神经网络当中。
2. 构建一个怎样的神经网络来做情感分类,才能迅速的得到一个准确率高的模型。
关于第一个问题
我在项目中采用的word2vec的方式来得到词向量的
具体的做法,我是使用gensim中的word2vec来做的
使用的方式很简单
# 保存模型训练和保存
from gensim.models import Word2Vec
model = Word2Vec(word2vec, sg=1, size=150, window=5, min_count=1, negative=1, sample=0.001, hs=1, workers=4)
model.save('model')
model就像python中的字典类型一样使用。
通过上面的方式我们可以得到词向量,但是我们怎么能够得到句向量呢。
下面提供几种思路,1.词向量的平均值,2.使用ti-idf做权重,求词向量的加权平均值,3. 使用seq2seq求句向量
至于哪种好吗,有人做过研究,其实平均值的做法其实就已经很不错了。更多内容请看下面的链接。
https://www.zhihu.com/question/29978268
关于第二个问题
目前我比较喜欢keras这个框架,相对tensorflow来说使用起来更简单,比较容易上手。
对于分类问题使用深度神经网络其实就已经可以做到了,当然使用RNN也是可以的,只是效果并不会更好。
from keras.models import Sequential
from keras.layers import Dense, Dropout
model = Sequential()
model.add(Dense(256, activation='relu' ,input_shape =(150,)))
model.add(Dropout(0.3))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='adadelta',
loss='binary_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train2,
y_train,
epochs=1000,
batch_size=256,
validation_split = 0.2)
整个模型的构建其实就是上面的过程,非常的简单明了。构建模型需要关注下面的点,神经网络需要多少层,每层需要的神经元个数。神经网络层之间是否使用**函数,如果要使用,该使用什么**函数,常用的**函数有tanh,sigmoid,relu等。如果训练模型的过程中出现过拟合问题,可以考虑使用dropout来减少神经元之间的连接来降低过拟合。优化器类型,我这里使用的是adadelta,当然也可以使用其他的优化器类型,如adagram,RMSprop,adam,nadam等,具体可以起keras的官网去找https://keras.io/zh/
关于损失函数的选择,因为是2分类问题,我这里使用的2分交叉熵损失函数。如果是多分类问题的的,可以使用多分类交叉熵损失函数categorical_crossentropy,如果此时预测的问题可以使用均方差损失函数mean_squared_error
这个问题也可以使用LSTM来做,甚至是多层lstm,双向lstm,或者是GRU模型来完成。
下面是代码展示:
#双向多层的lstm模型
model = Sequential()
model.add(Bidirectional(LSTM(100,return_sequences=True),
input_shape=(x_train2.shape[1], x_train2.shape[2])))
model.add(Bidirectional(LSTM(100)))
model.add(Dropout(0.2))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam',metrics=['accuracy'])
model.fit(x_train2,y_train,epochs=1000,batch_size=256,validation_split=0.2)
#GRU模型
model = Sequential()
model.add(GRU(150,dropout=0.2,recurrent_dropout=0.2,input_shape=(x_train2.shape[1], x_train2.shape[2])))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam',metrics=['accuracy'])
model.fit(x_train2,y_train,epochs=1000,batch_size=256,validation_split=0.2)
情感倾向值应该如何计算呢?
使用情感词库的方式来完成这个任务
使用波森情感词库,里面存放了大量的常用的中文词,已经对应的情感值。
当然只有这个是不够的,因为一句话中会有否定词或者是程度副词对情感词进行修饰,他们会影响情感的偏向和情感的程度。
使用方式:将玻森情感词典,加载到内存当中,形成一个字典结构A。对需要进行情感判断的句子进行分词,对分词后的结果,在A索引它的情感评分。所有词的情感评分累加就是最后的那句话的情感评分。但是上面的说法忽略了两个重要的问题:1. 没有考虑否定词对词语情感产生的影响,2.没有考虑程度副词对对情感的加权。如果将以上两点考虑进去,那么情感计算公式就应该是:情感值*(-1,如果有否定词修饰)*程度副词的权重w。需要的材料:否定词集,程度副词词集,情感词集,停词词集(可要可不要)
资料可在下面的百度网盘中下载
https://pan.baidu.com/s/1qpfJbANK6MYB71dQDEw0wg
扩展问题:
1. 如果构建自集的词向量模型?
下面我们采用词袋法的方式来介绍一下具体的操作流程
1. 试验数据的结构应该是怎么样的
假如窗口的大小是1,文本的内容是‘博客模块管理’,中心词是‘客’,那么这时的样本值就是(‘模块’,‘博客’),(‘模块’,‘管理’),他们都是从文本中取出来的样本值,都是正例,所以样本值是((‘模块’,‘博客’),1),((‘模块’,‘管理’),1),词向量的损失函数一般采用的是负例采样的方式nce,假如当前的负例样本库是['算法',‘图书’],那么就可以生成((‘模块’,‘算法’),0),((‘模块’,‘图书’),0),这样的负例样本。当然在构建词向量的时候,虽然‘模块’和‘博客’都是输入值,但是需要分开利用使用embedding表示。
图例如下
代码如下
#模型构建
word_model = Sequential()
word_model.add(Embedding(vocab_size, embed_size,
embeddings_initializer="glorot_uniform",
input_length=1))
word_model.add(Reshape((embed_size,)))
context_model = Sequential()
context_model.add(Embedding(vocab_size, embed_size,
embeddings_initializer="glorot_uniform",
input_length=1))
context_model.add(Reshape((embed_size,)))
model = Sequential()
model.add(Merge([word_model, context_model], mode="dot", dot_axes=0))
model.add(Dense(1, kernel_initializer="glorot_uniform", activation="sigmoid"))
model.compile(loss="mean_squared_error", optimizer="adam")
#从模型中取出词向量
merge_layer = model.layers[0]
print(model.layers)
word_model = merge_layer.layers[0]
print(word_model)
word_embed_layer = word_model.layers[0]
weights = word_embed_layer.get_weights()[0]
print(word_embed_layer.get_weights())
print(len(word_embed_layer.get_weights()))
weigths = word_embed_layer.get_weights()
import pandas as pd
上一篇: 学习KEA之时钟