前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Twitter情感分析CNN+word2vec(翻译)

Twitter情感分析CNN+word2vec(翻译)

作者头像
三猫
发布2018-07-23 17:32:54
1.5K0
发布2018-07-23 17:32:54
举报
文章被收录于专栏:机器学习养成记

Rickest Ricky 对Twitter内容做了一系列的文本分析处理,并把内容整理成博文发布到:https://medium.com/@rickykim78。本文是对他此项目第11部分的部分内容翻译,主要是通过CNN和word2vec进行文本分析,完整内容及代码可以在github上找到:https://github.com/tthustla/twitter_sentiment_analysis_part11/blob/ master/Capstone_part11.ipynb

准备工作

在上一篇文章中,通过求和或计算平均值,得到每个微博的一个词向量表示。然而,为了使用CNN,我们不仅要将每个单词向量馈送到模型中,还要考虑词序。比如考虑如下例子:

“I love cats”

我们假设有如下二维向量来表示每个词:

I: [0.3, 0.5] love: [1.2, 0.8] cats: [0.4, 1.3]

因此用来表示整个句子的向量维度就是3*2(3:单词数,2:词向量维度)。

这样就会带来一个问题,因为神经网络中,要求数据都有相同都维数,但是句子不同,维数就会不一样。可以用填充的方法解决这个问题。比如说这个句子:

“I love dogs too”

每个词的表示向量为:

I: [0.3, 0.5], love: [1.2, 0.8], dogs: [0.8, 1.2], too: [0.1, 0.1]

第一个句子是一个3*2的向量,但是第二个句子对应的是一个4*2的向量。神经网络无法处理这样的输入,通过填充,我们规定每个句子单词数的上限,当每句的单词数少于这个上限时,用0进行填充。如果长度超过上限,就进行截断。比如,假设上限长度为5,对于第一个句子,用两个2维零向量填充到开头或者结尾,对于第二个句子,用一个2维零向量填充到开头或结尾。这样我们就有两个5*2向量,因此可以将他们输入到模型中。

首先加载word2vec模型,提取单词向量。

代码语言:javascript
复制
from gensim.models import KeyedVectors
model_ug_cbow = KeyedVectors.load('w2v_model_ug_cbow.word2vec')
model_ug_sg = KeyedVectors.load('w2v_model_ug_sg.word2vec')

通过运行下面的代码块,构造一种字典来提取词向量。由于我有两个不同的Word2VEC模型,下面的代码将两个模型的向量连接。对于每个模型,用100维向量表示的单词,通过连接,每个单词将有200维向量表示。

代码语言:javascript
复制
embeddings_index = {}for w in model_ug_cbow.wv.vocab.keys():
    embeddings_index[w] = np.append(model_ug_cbow.wv[w],model_ug_sg.wv[w])
print('Found %s word vectors.' % len(embeddings_index))

现在已经有了词向量,但是还没能把他们转化为文章开始时说的格式。可以用如下代码进行转化:

代码语言:javascript
复制
from keras.preprocessing.text 
import Tokenizerfrom keras.preprocessing.sequence 
import pad_sequences
tokenizer = Tokenizer(num_words=100000)
tokenizer.fit_on_texts(x_train)
sequences = tokenizer.texts_to_sequences(x_train)

下面对维度进行扩充,上限设置为45:

代码语言:javascript
复制
x_train_seq = pad_sequences(sequences, maxlen=45)
x_train_seq[:5]

可以得到如下形式数据

所有数据都被转化为相同的长度,根据默认,零向量在开头处进行填充。当我们把句子转化为词序向量时,每个词是用整数表示的,实际上,这些数字是每个单词存储在记录器的单词索引中的地方。用单词索引号构建这些单词向量的矩阵,使我们的模型可以在输入整数序列时参考相应的向量,是把数据输入模型前还需要进行的处理。

下面,我定义的单词数是100000。这意味着我只关心训练集中最常用的100000个单词。如果不限制单词的数量,词汇量将超过200000。

代码语言:javascript
复制
num_words = 100000
embedding_matrix = np.zeros((num_words, 200))
for word, i in tokenizer.word_index.items():
    if i >= num_words:
        continue
    embedding_vector = embeddings_index.get(word)
    if embedding_vector is not None:
        embedding_matrix[i] = embedding_vector

CNN

CNN在图像数据的处理上有很多应用,那文字数据应该如何使用CNN呢?我们看如下例子:

“I love cats and dogs”

假设词向量是200维的,那上面的句子可以表示为一个5*200的矩阵,每行表示为一个单词。如果句子单词数上限为45,那么我们还要为其填充40个零向量,把上述句子最终表示为45*200的矩阵。从下图,可以看出CNN是如何处理图片数据的。

从上图可以看出,通过3*3的过滤器把图像数据进行卷积,计算矩阵乘法的和,并将结果记录在特征映射(输出矩阵)上。如果我们假设数据的每一行是一个句子中的一个单词,那么它将不能有效地学习,因为过滤器只看一个词向量的一部分。上述CNN被叫做2维卷积神经网络,因为过滤器在2维空间中作用。

我们用字向量表示的文本数据是利用一维卷积神经网络。如果过滤器的列宽度和数据的列宽度一致,那么它就没有空间可以水平地变换,只能垂直变换。例如,如果我们的句子以45×200矩阵表示,那么一个过滤列宽度也将有200列,行(高度)数近似于n元的概念。如果一个2*200的过滤器作用在一个45*200的矩阵,会得到一个44*1的输出。在一维卷积下,输出宽度为1.下面我们增加一维卷积的过滤器数,当我们使用100个2*200的过滤器,将会得到一个44*100的输出结果。

代码语言:javascript
复制
from keras.layers import Conv1D, GlobalMaxPooling1D
代码语言:javascript
复制
structure_test = Sequential()e = Embedding(100000, 200, input_length=45)structure_test.add(e)structure_test.add(Conv1D(filters=100, kernel_size=2, padding='valid', activation='relu', strides=1))structure_test.summary()

下面让我们建立一个简单的CNN:

代码语言:javascript
复制
model_cnn_01 = Sequential()
e = Embedding(100000, 200, weights=[embedding_matrix], input_length=45, trainable=False)
model_cnn_01.add(e)
model_cnn_01.add(Conv1D(filters=100, kernel_size=2, padding='valid', activation='relu', strides=1))
model_cnn_01.add(GlobalMaxPooling1D())
model_cnn_01.add(Dense(256, activation='relu'))
model_cnn_01.add(Dense(1, activation='sigmoid'))
model_cnn_01.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model_cnn_01.fit(x_train_seq, y_train, validation_data=(x_val_seq, y_validation), epochs=5, batch_size=32, verbose=2)
代码语言:javascript
复制
model_cnn_02 = Sequential()
e = Embedding(100000, 200, input_length=45)
model_cnn_02.add(e)
model_cnn_02.add(Conv1D(filters=100, kernel_size=2, padding='valid', activation='relu', strides=1))
model_cnn_02.add(GlobalMaxPooling1D())model_cnn_02.add(Dense(256, activation='relu'))
model_cnn_02.add(Dense(1, activation='sigmoid'))
model_cnn_02.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model_cnn_02.fit(x_train_seq, y_train, validation_data=(x_val_seq, y_validation), epochs=5, batch_size=32, verbose=2)
代码语言:javascript
复制
model_cnn_03 = Sequential()
e = Embedding(100000, 200, weights=[embedding_matrix], input_length=45, trainable=True)
model_cnn_03.add(e)
model_cnn_03.add(Conv1D(filters=100, kernel_size=2, padding='valid', activation='relu', strides=1))
model_cnn_03.add(GlobalMaxPooling1D())
model_cnn_03.add(Dense(256, activation='relu'))
model_cnn_03.add(Dense(1, activation='sigmoid'))
model_cnn_03.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model_cnn_03.fit(x_train_seq, y_train, validation_data=(x_val_seq, y_validation), epochs=5, batch_size=32, verbose=2)

结果显示,第三个模型效果最好,精度达到83.25%。

推荐文章

· Bagging算法(R语言)

· R语言爬虫与文本分析

· 静态爬虫与地址经纬度转换(python)

· 特征工程(一):前向逐步回归(R语言)

· 聚类(三):KNN算法(R语言)

· 小案例(六):预测小偷行为(python)

· ggplot2:正负区分条形图及美化

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器学习养成记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档