背景简介
本人是深度学习入门的菜菜菜鸟一枚… 利用LSTM + word2vec词向量进行文本情感分类/情感分析实验,吸收了网上的资源和代码并尝试转化为自己的东西~
实验环境
win7 64位系统Anaconda 4.3.0 , Python 2.7 versionPycharm开发环境python包:keras,gensim,numpy等
实验数据
本文的实验数据是来自网上的中文标注语料,涉及书籍、酒店、计算机、牛奶、手机、热水器六个方面的购物评论数据,具体介绍参见该文:购物评论情感分析。
数据处理
上面提到的数据在网上见到的次数比较多,原始格式是两个excel文件,如图:
对,就是这两个…估计来到本文的小伙伴也见过。一些代码就是直接从这两个excel里读取数据、分词、处理…不过我表示自己习惯从txt文本里获取数据,因此本人将数据合并、去重(原数据里有不少重复的评论)、分词(用的是哈工大LTP分词)之后存为一份txt文本,保留的数据情况如下:
正面评价个数:8680个 负面评价个数:8000个
文本如图所示:
然后人工生成一份【语料类别】文本,用1表示正面评价,用0表示负面评价,与评论数据一一对应。
生成词语的索引字典、词向量字典
利用上述文本语料生成词语的索引字典和词向量字典。 注意:当Word2vec词频阈值设置为5时,词频小于5的词语将不会生成索引,也不会生成词向量数据。
工具:gensim里的Word2vec,Dictionary
代码
"""
功能:利用大语料生成词语的索引字典、词向量,然后保存为pkl文件
时间:2017年3月8日 13:19:40
"""
import pickle
import logging
import tkFileDialog
import numpy
as np
np.random.seed(
1337)
from Functions.TextSta
import TextSta
from gensim.models.word2vec
import Word2Vec
from gensim.corpora.dictionary
import Dictionary
def create_dictionaries(p_model):
gensim_dict = Dictionary()
gensim_dict.doc2bow(p_model.vocab.keys(), allow_update=
True)
w2indx = {v: k +
1 for k, v
in gensim_dict.items()}
w2vec = {word: model[word]
for word
in w2indx.keys()}
return w2indx, w2vec
logging.basicConfig(format=
'%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
print u"请选择大语料的分词文本..."
T = TextSta(tkFileDialog.askopenfilename(title=
u"选择文件"))
sentences = T.sen()
print u'训练Word2vec模型(可尝试修改参数)...'
model = Word2Vec(sentences,
size=
100,
min_count=
5,
window=
5)
model_name = raw_input(
u"请输入保存的模型文件名...\n").decode(
"utf-8")
model.save(model_name +
u'.model')
index_dict, word_vectors= create_dictionaries(model)
pkl_name = raw_input(
u"请输入保存的pkl文件名...\n").decode(
"utf-8")
output = open(pkl_name +
u".pkl",
'wb')
pickle.dump(index_dict, output)
pickle.dump(word_vectors, output)
output.close()
if __name__ ==
"__main__":
pass
其中,
T = TextSta(tkFileDialog.askopenfilename(title=
u"选择文件"))
sentences = T.sen()
TextSta是我自己写的一个类,读取语料文本后,sentences = T.sen()将文本里的每一行生成一个列表,每个列表又是词汇的列表。(这个类原来是用作句子分类的,每行是一个句子;这里每行其实是一个评论若干个句子…我就不改代码变量名了…)
TextSta类部分代码:
"""
功能:一个类,执行文本转换
输入:分词文本
输出:句子列表,全文的词汇列表,TF,DF
时间:2016年5月17日 19:08:34
"""
import codecs
import re
import tkFileDialog
class TextSta:
filename =
""
def __init__(self, path):
self.filename = path
def sen(self):
f1 = codecs.open(self.filename,
"r", encoding=
"utf-8")
print u"已经打开文本:", self.filename
sentences_list = []
for line
in f1:
single_sen_list = line.strip().split(
" ")
while "" in single_sen_list:
single_sen_list.remove(
"")
sentences_list.append(single_sen_list)
print u"句子总数:", len(sentences_list)
f1.close()
return sentences_list
if __name__ ==
"__main__":
pass
总之,sentences的格式如下:
[[我, 是, 2月, …], [#, 蒙牛, 百, …], …]
所有的评论文本存为一个列表,每个评论文本又是词汇的列表。 sentences列表的长度就是文本的行数:len(sentences) = 16680
利用Keras + LSTM进行文本分类
工具:Keras深度学习库
代码:
"""
功能:利用词向量+LSTM进行文本分类
时间:2017年3月10日 21:18:34
"""
import numpy
as np
np.random.seed(
1337)
import pickle
from keras.preprocessing
import sequence
from keras.models
import Sequential
from keras.layers.embeddings
import Embedding
from keras.layers.recurrent
import LSTM
from keras.layers.core
import Dense, Dropout, Activation
from sklearn.cross_validation
import train_test_split
from Functions
import GetLineList
from Functions.TextSta
import TextSta
vocab_dim =
100
maxlen =
140
batch_size =
32
n_epoch =
5
input_length =
140
def text_to_index_array(p_new_dic, p_sen):
new_sentences = []
for sen
in p_sen:
new_sen = []
for word
in sen:
try:
new_sen.append(p_new_dic[word])
except:
new_sen.append(
0)
new_sentences.append(new_sen)
return np.array(new_sentences)
def train_lstm(p_n_symbols, p_embedding_weights, p_X_train, p_y_train, p_X_test, p_y_test):
print u'创建模型...'
model = Sequential()
model.add(Embedding(output_dim=vocab_dim,
input_dim=p_n_symbols,
mask_zero=
True,
weights=[p_embedding_weights],
input_length=input_length))
model.add(LSTM(output_dim=
50,
activation=
'sigmoid',
inner_activation=
'hard_sigmoid'))
model.add(Dropout(
0.5))
model.add(Dense(
1))
model.add(Activation(
'sigmoid'))
print u'编译模型...'
model.compile(loss=
'binary_crossentropy',
optimizer=
'adam',
metrics=[
'accuracy'])
print u"训练..."
model.fit(p_X_train, p_y_train, batch_size=batch_size, nb_epoch=n_epoch,
validation_data=(p_X_test, p_y_test))
print u"评估..."
score, acc = model.evaluate(p_X_test, p_y_test, batch_size=batch_size)
print 'Test score:', score
print 'Test accuracy:', acc
f = open(
u"评价语料索引及词向量.pkl",
'rb')
index_dict = pickle.load(f)
word_vectors = pickle.load(f)
new_dic = index_dict
print u"Setting up Arrays for Keras Embedding Layer..."
n_symbols = len(index_dict) +
1
embedding_weights = np.zeros((n_symbols,
100))
for w, index
in index_dict.items():
embedding_weights[index, :] = word_vectors[w]
print u"请选择语料的分词文本..."
T1 = TextSta(
u"评价语料_分词后.txt")
allsentences = T1.sen()
print u"请选择语料的类别文本...(用0,1分别表示消极、积极情感)"
labels = GetLineList.main()
X_train_l, X_test_l, y_train_l, y_test_l = train_test_split(allsentences, labels, test_size=
0.2)
X_train = text_to_index_array(new_dic, X_train_l)
X_test = text_to_index_array(new_dic, X_test_l)
print u"训练集shape: ", X_train.shape
print u"测试集shape: ", X_test.shape
y_train = np.array(y_train_l)
y_test = np.array(y_test_l)
print(
'Pad sequences (samples x time)')
X_train = sequence.pad_sequences(X_train, maxlen=maxlen)
X_test = sequence.pad_sequences(X_test, maxlen=maxlen)
print(
'X_train shape:', X_train.shape)
print(
'X_test shape:', X_test.shape)
train_lstm(n_symbols, embedding_weights, X_train, y_train, X_test, y_test)
if __name__ ==
"__main__":
pass
其中,
from Functions
import GetLineList
GetLineList是自定义模块,用于获取文本的类别(存为列表),代码如下:
"""
功能:文本转列表,常用于读取词典(停用词,特征词等)
使用:给定一个文本,将文本按行转换为列表,每行对应列表里的一个元素
时间:2016年5月15日 22:45:23
"""
import codecs
import tkFileDialog
def main():
file_path = tkFileDialog.askopenfilename(title=
u"选择文件")
f1 = codecs.open(file_path,
"r", encoding=
"utf-8")
print u"已经打开文本:", file_path
line_list = []
for line
in f1:
line_list.append(line.strip())
print u"列表里的元素个数:", len(line_list)
f1.close()
return line_list
if __name__ ==
"__main__":
pass
实验结果
参考文献:
http://buptldy.github.io/2016/07/20/2016-07-20-sentiment analysis/ https://github.com/BUPTLdy/Sentiment-Analysis