本篇文章的靈感主要來自于Kaggle上的一個(gè)叫做Sentiment analysis on IMDB movie reviews比賽。同時(shí)采用了IMDB數(shù)據(jù)集。想要該數(shù)據(jù)集的可以進(jìn)行下載。
??首先寫介紹一下本次文章的主要內(nèi)容。簡單來說就是判斷電影評(píng)論內(nèi)容的極性(也就是差評(píng)還是好評(píng))。所以該極性也就可以只分為兩種可能性(0或者1)。同時(shí)本篇文章主要是基于Keras中LSTM 進(jìn)行極性判斷。
??接下來先看一下數(shù)據(jù)集長什么樣子。。。。

??這只是極少部分?jǐn)?shù)據(jù)集。詳細(xì)數(shù)據(jù)集可以自行下載參觀欣賞把玩。簡單概括一下該數(shù)據(jù)集。其中分為兩個(gè)部分,第一部分是test dataset(測試數(shù)據(jù)集),第二部分是train dataset(訓(xùn)練數(shù)據(jù)集),其中在train dataset中分為neg,pos兩個(gè)部分(neg:negative消極的,pos:positive積極的)。所以我們需要做的事情就是將這兩個(gè)數(shù)據(jù)集進(jìn)行訓(xùn)練出一個(gè)模型同時(shí)進(jìn)行test數(shù)據(jù)集的測試。
??因?yàn)閯偰玫綌?shù)據(jù)我們可以發(fā)現(xiàn)這是由幾萬個(gè)單獨(dú)的txt文本組成的文件夾。那么第一步就是將這些文件合并成一個(gè)。代碼如下所示:
# -*- coding: utf-8 -*-
import os
import codecs
pos_location='C:/Users/john/Desktop/情感分析/aclImdb_v1/aclImdb/train/pos'
pos_files=os.listdir(pos_location)
neg_location='C:/Users/john/Desktop/情感分析/aclImdb_v1/aclImdb/train/neg'
neg_files=os.listdir(neg_location)
pos_all=codecs.open('C:/Users/john/Desktop/情感分析/aclImdb_v1/aclImdb/train/pos_all.txt','a',encoding='utf8')
neg_all=codecs.open('C:/Users/john/Desktop/情感分析/aclImdb_v1/aclImdb/train/neg_all.txt','a',encoding='utf8')
all=[]
for file in pos_files:
whole_location=os.path.join(pos_location,file)
with open(whole_location,'r',encoding='utf8') as f:
line=f.readlines()
all.extend(line)
for file in all:
pos_all.write(file)
pos_all.write('\n')
alls=[]
for file in neg_files:
whole_location=os.path.join(neg_location,file)
with open(whole_location,'r',encoding='utf8') as f:
line=f.readlines()
alls.extend(line)
for file in alls:
neg_all.write(file)
neg_all.write('\n')
??通過上述代碼我們可以得到整體的txt文本如下所示:

??接下來就開始步入正題了。。。第一步先把所有能用上的庫導(dǎo)進(jìn)去。
from keras.preprocessing.text import Tokenizer
from keras.models import Sequential
from keras.layers.core import Dense,Activation
from keras.layers.embeddings import Embedding
from keras.layers.recurrent import LSTM
from keras.preprocessing import sequence
from sklearn.model_selection import train_test_split
import nltk
from nltk.corpus import stopwords
import collections
import pandas as pd
import numpy as np
import os
import codecs
??現(xiàn)在先不對(duì)這些庫進(jìn)行仔細(xì)的講解,接下來用到哪個(gè)庫我會(huì)再詳細(xì)的說一下。第二步引進(jìn)數(shù)據(jù)。
pos_list=[]
# pos=codecs.open('C:/Users/john/Desktop/情感分析/aclImdb_v1/aclImdb/train/pos_all.txt','r')
with open('C:/Users/john/Desktop/情感分析/aclImdb_v1/aclImdb/train/pos_all.txt','r',encoding='utf8')as f:
line=f.readlines()
pos_list.extend(line)
neg_list=[]
with open('C:/Users/john/Desktop/情感分析/aclImdb_v1/aclImdb/train/neg_all.txt','r',encoding='utf8')as f:
line=f.readlines()
neg_list.extend(line)
#創(chuàng)建標(biāo)簽
label=[1 for i in range(12500)]
label.extend([0 for i in range(12499)])
#評(píng)論內(nèi)容整合
content=pos_list.extend(neg_list)
content=pos_list
??這樣我們就完美的導(dǎo)入了數(shù)據(jù)。同時(shí)通過簡單的代碼len(neg_list)和len(pos_list)可以發(fā)現(xiàn)總共數(shù)據(jù)量是24999。多么強(qiáng)迫癥的數(shù)據(jù)量(PS.為啥不是25000。。。)
??如果大家有一些自然語言處理的相關(guān)知識(shí)的話,應(yīng)該對(duì)停用詞和標(biāo)點(diǎn)符號(hào)有一定的了解。一般來說。在拿到數(shù)據(jù)集的時(shí)候我們需要對(duì)數(shù)據(jù)集進(jìn)行預(yù)處理。其中就包含對(duì)原始數(shù)據(jù)集去停用詞和去標(biāo)點(diǎn)符號(hào)。這樣做的原因就是為了去噪音提高準(zhǔn)確度。那么接下來就需要進(jìn)行這一步的操作了。
seq=[]
seqtence=[]
stop_words=set(stopwords.words('english'))
for con in content:
words=nltk.word_tokenize(con)
line=[]
for word in words:
if word.isalpha() and word not in stop_words:
line.append(word)
seq.append(line)
seqtence.extend(line)
??這樣我們就可以得到相對(duì)干凈的數(shù)據(jù)集。如果你不進(jìn)行這一步的話,你會(huì)發(fā)現(xiàn)詞匯量是11萬多。但是通過去停用詞和去標(biāo)點(diǎn)符號(hào)之后,詞匯量變成了小9萬。這樣就極大的減少我們的工作量。其實(shí)進(jìn)行完該步驟的話。我們就已經(jīng)完成了一大部分。因?yàn)橛?jì)算機(jī)只能識(shí)別數(shù)字。所以我們需要把單詞轉(zhuǎn)換為數(shù)字。(其實(shí)在英文和中文進(jìn)行情感分析時(shí)該步驟都是必要的。),但是不要認(rèn)為這個(gè)步驟很難。其實(shí)so easy。
# 獲取詞索引
word_index=tokenizer.word_index
sequences=tokenizer.texts_to_sequences(seq)
# 此處設(shè)置每個(gè)句子最長不超過 800
final_sequences=sequence.pad_sequences(sequences,maxlen=800)
??上述代碼主要是為了轉(zhuǎn)換詞索引同時(shí)設(shè)置每個(gè)句子長度不超過800。超出就截?cái)?。不夠就補(bǔ)0.做完該步驟之后接下來還有一個(gè)問題就是。我們的原始數(shù)據(jù)集分布都是順序的。也就是說先是pos然后是neg。那么直接輸入這些數(shù)據(jù)其實(shí)是有問題的。我們需要打亂數(shù)據(jù)再進(jìn)行數(shù)據(jù)輸入(使其離散)。
# 轉(zhuǎn)換為numpy類型
label=np.array(label)
# 隨機(jī)打亂數(shù)據(jù)
indices=np.random.permutation(len(final_sequences))
X=final_sequences[indices]
y=label[indices]
# 劃分測試集和訓(xùn)練集
Xtrain,Xtest,ytrain,ytest=train_test_split(X,y,test_size=0.2)
??這樣我們就完美的劃分好測試集和訓(xùn)練集了。已經(jīng)很接近勝利了。。接下來就是LSTM網(wǎng)絡(luò)搭建了。
# 網(wǎng)絡(luò)構(gòu)建
model=Sequential()
model.add(Embedding(89483,256,input_length=800))
model.add(LSTM(128,dropout=0.2))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])
model.fit(Xtrain,ytrain,batch_size=32,epochs=10,validation_data=(Xtest,ytest))
??任務(wù)結(jié)束。上述代碼就是完整的LSTM搭建。是不是很簡單。。其實(shí)從這里我們也看出來了很多數(shù)據(jù)分析難就難在數(shù)據(jù)預(yù)處理上。同時(shí)準(zhǔn)確率也很依賴數(shù)據(jù)預(yù)處理。接下來就是展示一下最終結(jié)果:

??此處我總共進(jìn)行了10次迭代?;ㄙM(fèi)了大概40分鐘左右吧。。。但是可以發(fā)現(xiàn)在測試集上最高準(zhǔn)確率可以達(dá)到87.5%。這個(gè)結(jié)果還是不錯(cuò)的。就是時(shí)間很蛋疼。。大家完全趁這個(gè)時(shí)間打一把lol是沒有問題的。。。。。。