很早之前就想写一篇关于用深度学习做情感分析的文章,一直拖到现在,拖延症啊。。。。
什么是情感分析?
情感分析(Sentiment analysis)是自然语言处理(NLP)领域的一个任务,又称倾向性分析,意见抽取(Opinion extraction),意见挖掘(Opinion mining),情感挖掘(Sentiment mining),主观分析(Subjectivity analysis)等,它是对带有情感色彩的主观性文本进行分析、处理、归纳和推理的过程,如从电影评论中分析用户对电影的评价(positive、negative),从商品评论文本中分析用户对商品的“价格、大小、重 量、易用性”等属性的情感倾向。
情感分析的主要方法
现阶段主要的情感分析方法主要有两类:
基于词典的方法:该方法主要通过制定一系列的情感词典和规则,对文本进行段落拆解、句法分析,计算情感值,最后通过情感值来作为文本的情感倾向依据。
基于机器学习的方法:这种方法又分为(1)基于传统机器学习的方法;(2)基于深度学习的方法。
该方法大多将问题转化为一个分类问题来看待,对于情感极性的判断,将目标情感分类2类:正、负,或者根据不同程度分为1-5类。对训练文本进行人工标标注,然后进行有监督的机器学习过程。
基于词典的方法和基于传统机器学习的方法可以参考这篇文章(点击打开链接)
本文主要基于深度学习方法对IMDB电影评论进行分析,这其实是一个分类问题,将IMDB电影评论分为正面评价(positive)和负面评价(negative)。
本文将用三种方法循序渐进地讲述使用深度学习对IMDB评论进行情感分析。这三种方法为:MLP、BiRNN(LSTM、GRU)、BiGRU+Attention,IMDB的数据集可以从这里(点击打开链接)下载。使用的深度学习框架是Keras,后端是TensorFlow,在GPU服务器上运行,GPU服务器型号是TITAN X。
详细的代码可以在我的GitHub上获取(点击打开链接),欢迎fork和star。
基于深度学习方法的IMDB情感分析——数据预处理
IMDB电影评论数据总共有25000条,如果你是在上面的链接中下载的数据,那么数据的组织格式就是下图所示(review是评论文本,sentiment是情感分类标注,1代表positive,0代表negative):
在读出数据之后,需要对数据进行一些处理,例如过滤掉一些非ASCII字符,清洗掉一些换行符,将大写字母转换为小写等:
def clean_str(string):
"""
Tokenization/string cleaning for dataset
Every dataset is lower cased except
"""
string = re.sub(r"\\", "", string)
string = re.sub(r"\'", "", string)
string = re.sub(r"\"", "", string)
return string.strip().lower()
data_train = pd.read_csv('/data/mpk/IMDB/labeledTrainData.tsv', sep='\t')
print data_train.shape
texts = []
labels = []
for idx in range(data_train.review.shape[0]):
text = BeautifulSoup(data_train.review[idx], "lxml")
texts.append(clean_str(text.get_text().encode('ascii','ignore')))
labels.append(data_train.sentiment[idx])
labels = to_categorical(np.asarray(labels))
将数据序列化,并统一长度(这里统一句子长度为1000,多的截断,少的补0):
tokenizer = Tokenizer(nb_words=MAX_NB_WORDS)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
word_index = tokenizer.word_index
data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
随机打乱数据,并将数据切分为训练集和验证集(切分比例8:2):
indices = np.arange(data.shape[0])
np.random.shuffle(indices)
data = data[indices]
labels = labels[indices]
nb_validation_samples = int(VALIDATION_SPLIT * data.shape[0])
x_train = data[:-nb_validation_samples]
y_train = labels[:-nb_validation_samples]
x_val = data[-nb_validation_samples:]
y_val = labels[-nb_validation_samples:]
将数据序列化之后,每一句话就变成了固定长度(1000)的index序列,每一个index对应一个词语。接下来我们将index对应到词语的word Embedding(词向量),这里使用的是glove.6B.100d,即每个词用100维向量表示,glove词向量可以在这里(点击打开链接)下载。未登录词(OOV问题)采取的是随机初始化向量,词向量不可训练。
GLOVE_DIR = "/data/mpk"
embeddings_index = {}
f = open(os.path.join(GLOVE_DIR, 'glove.6B.100d.txt'))
for line in f:
values = line.split()
word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
embeddings_index[word] = coefs
f.close()
print('Total %s word vectors.' % len(embeddings_index))
embedding_matrix = np.random.random((len(word_index) + 1, EMBEDDING_DIM))
for word, i in word_index.items():
embedding_vector = embeddings_index.get(word)
if embedding_vector is not None:
# words not found in embedding index will be all-zeros.
embedding_matrix[i] = embedding_vector
print ('Length of embedding_matrix:', embedding_matrix.shape[0])
embedding_layer = Embedding(len(word_index) + 1,
EMBEDDING_DIM,
weights=[embedding_matrix],
mask_zero=False,
input_length=MAX_SEQUENCE_LENGTH,
trainable=False)
基于深度学习方法的IMDB情感分析——MLP
基于多层感知器(MLP)对IMDB进行分类是非常简单的一种神经网络应用,关于MLP的原理及Keras实现参见我的这篇文章(点击打开链接)。
在得到文本向量表示之后,可以直接将向量输入MLP网络,经过多层MLP训练之后,进行softmax分类。代码如下:
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
embedded_sequences = embedding_layer(sequence_input)
dense_1 = Dense(100,activation='tanh')(embedded_sequences)
max_pooling = GlobalMaxPooling1D()(dense_1)
dense_2 = Dense(2, activation='softmax')(max_pooling)
model = Model(sequence_input, dense_2)
model.compile(loss='categorical_