【NLP】使用堆疊雙向 LSTM 進(jìn)行情感分析
情緒分析
情感分析是發(fā)現(xiàn)文本數(shù)據(jù)的情感的過程。情感分析屬于自然語言處理中的文本分類。情緒分析將幫助我們更好地了解我們的客戶評論。
情緒的性質(zhì)有:正面、負(fù)面和中性。當(dāng)我們分析產(chǎn)品的負(fù)面評論時,我們可以使用這些評論來克服我們面臨的問題并提供更好的產(chǎn)品。

使用情感分析的好處包括:
更好地了解客戶
根據(jù)客戶評論改進(jìn)產(chǎn)品功能
我們將能夠識別功能中的錯誤并解決它們以使客戶滿意。
情感分析可以通過兩種不同的方式進(jìn)行:
基于規(guī)則的情感分析
自動化情緒分析
在基于規(guī)則的情感分析中,我們定義了一組規(guī)則,如果數(shù)據(jù)滿足這些規(guī)則,那么我們可以對它們進(jìn)行相應(yīng)的分類。
例如,如果文本數(shù)據(jù)包含好、漂亮、驚人等詞,我們可以將其歸類為積極情緒。基于規(guī)則的情感分析的問題在于它不能很好地概括并且可能無法準(zhǔn)確分類。
例如,基于規(guī)則的系統(tǒng)更有可能根據(jù)規(guī)則將以下句子歸類為正面,“The product is not good”。原因是基于規(guī)則的系統(tǒng)識別出句子中的單詞 good 并將其歸類為積極情緒,但上下文不同,句子是消極的。
為了克服這些問題,我們可以使用深度學(xué)習(xí)技術(shù)進(jìn)行情感分析。
在自動情感分析中,我們利用深度學(xué)習(xí)來學(xué)習(xí)數(shù)據(jù)中的特征-目標(biāo)映射。在我們的例子中,特征是評論,目標(biāo)是情緒。因此,在我們的文章中,我們使用深度學(xué)習(xí)模型來進(jìn)行自動情感分析。
使用 TensorFlow 進(jìn)行情感分析
在這篇文章中,我們將利用深度學(xué)習(xí)來發(fā)現(xiàn) IMDB 評論的情緒。我們將在這篇文章中使用 IMDB 評論數(shù)據(jù)。你可以在此處(https://www.kaggle.com/lakshmi25npathi/imdb-dataset-of-50k-movie-reviews)下載數(shù)據(jù)。
數(shù)據(jù)包含兩列,即評論和情緒。情緒列僅包含兩個值,即正面和負(fù)面,表示相應(yīng)評論的情緒。所以我們可以推斷我們的問題是一個二元分類問題。我們的模型將學(xué)習(xí)特征-目標(biāo)映射,在我們的例子中,它是評論-情緒映射。
在這篇文章中,我們將使用 regex 和 spaCy 進(jìn)行預(yù)處理,使用 TensorFlow 的雙向 LSTM 模型進(jìn)行訓(xùn)練。
要安裝 spaCy,請參閱此(https://spacy.io/usage#installation)網(wǎng)頁以獲取說明。
要安裝 TensorFlow,請參閱此(https://www.tensorflow.org/install)網(wǎng)頁以獲取說明。
安裝 spaCy 后,使用以下命令下載名為 en_core_web_sm 的 spaCy 的訓(xùn)練管道包,我們將使用它進(jìn)行預(yù)處理。
python?-m?spacy?download?en_core_web_sm
導(dǎo)入所需的庫
import?re
import?spacy
import?numpy?as?np
import?pandas?as?pd
import?en_core_web_sm
import?tensorflow?as?tf
from?nltk.stem?import?WordNetLemmatizer
from?tensorflow.keras.optimizers?import?Adam
from?tensorflow.keras.models?import?Sequential
from?spacy.lang.en.stop_words?import?STOP_WORDS
from?tensorflow.keras.preprocessing.text?import?Tokenizer
from?tensorflow.keras.preprocessing.sequence?import?pad_sequences
from?tensorflow.keras.layers.experimental.preprocessing?import?TextVectorization
from?tensorflow.keras.layers?import?Embedding,?LSTM,?Dense,?Bidirectional,?Dropout
nlp?=?en_core_web_sm.load()
lemmatizer?=?WordNetLemmatizer()
stopwords?=?STOP_WORDS
EMOJI_PATTERN?=?re.compile(
????"["
????u"U0001F600-U0001F64F"??#?emoticons
????u"U0001F300-U0001F5FF"??#?symbols?&?pictographs
????u"U0001F680-U0001F6FF"??#?transport?&?map?symbols
????u"U0001F1E0-U0001F1FF"??#?flags?(iOS)
????u"U00002702-U000027B0"
????u"U000024C2-U0001F251"
????"]+",?flags=re.UNICODE
)
FILTERS?=?'!"#$%&()*+,-/:;?@[\]^_`{|}~tn'
HTML_TAG_PATTERN?=?re.compile(r']*>')
NUMBERING_PATTERN?=?re.compile('d+(?:st|[nr]d|th)')
DISABLE_PIPELINES?=?["tok2vec",?"parser",?"ner",?"textcat",?"custom",?"lemmatizer"]
我們正在使用命令 en_core_web_sm.load() 加載 spaCy 的訓(xùn)練管道 en_core_web_sm。我們還加載了 spaCy 中可用的停用詞。停用詞是沒有太多意義的詞,一些例子包括像 the、he、she、it 等詞。
上面定義的表情符號模式EMOJI_PATTERN用于刪除評論數(shù)據(jù)中的表情符號。
上面定義的過濾器FILTERS是評論中可能提供的特殊字符。
上面定義的 HTML 標(biāo)記模式(HTML_TAG_PATTERN)用于刪除 HTML 標(biāo)記并僅保留標(biāo)記內(nèi)的數(shù)據(jù)。
上面定義的編號模式NUMBERING_PATTERN用于刪除編號,如 1st、2nd、3rd 等。
上面定義的禁用管道DISABLE_PIPELINES用于禁用 spaCy 語言模型中的某些管道,從而高效且低延遲地完成處理。
def?initial_preprocessing(text):
????"""
????-?Remove?HTML?tags
????-?Remove?Emojis
????-?For?numberings?like?1st,?2nd
????-?Remove?extra?characters?>?2?eg:
????ohhhh?to?ohh
????"""
????tag_removed_text?=?HTML_TAG_PATTERN.sub('',?text)
????emoji_removed_text?=?EMOJI_PATTERN.sub(r'',?tag_removed_text)
????numberings_removed_text?=??NUMBERING_PATTERN.sub('',?emoji_removed_text)
????extra_chars_removed_text?=?re.sub(
????????r"(.)1{2,}",??r'11',?numberings_removed_text
????)
????return?extra_chars_removed_text
def?preprocess_text(doc):
????"""
????Removes?the?
????1.?Spaces
????2.?Email
????3.?URLs
????4.?Stopwords
????5.?Punctuations
????6.?Numbers
????"""
????tokens?=?[
????????token
????????for?token?in?doc
????????if?not?token.is_space?and
???????????not?token.like_email?and
???????????not?token.like_url?and
???????????not?token.is_stop?and
???????????not?token.is_punct?and
???????????not?token.like_num
????]
????"""
????Remove?special?characters?in?tokens?except?dot
????(would?be?useful?for?acronym?handling)
????"""
????translation_table?=?str.maketrans('',?'',?FILTERS)
????translated_tokens?=?[
????????token.text.lower().translate(translation_table)
????????for?token?in?tokens
????]
????"""
????Remove?integers?if?any?after?removing?
????special?characters,?remove?single?characters?
????and?lemmatize
????"""
????lemmatized_tokens?=?[
????????lemmatizer.lemmatize(token)
????????for?token?in?translated_tokens
????????if?len(token)?>?1
????]
????return?lemmatized_tokens
labels?=?imdb_data['sentiment'].iloc[:10000]
labels?=?labels.map(lambda?x:?1?if?x=='positive'?else?0)
"""
Preprocess?the?text?data
"""
data?=?imdb_data.iloc[:10000,?:]
column?=?'review'
not_null_data?=?data[data
.notnull()]
not_null_data
?=?not_null_data
.apply(initial_preprocessing)
texts?=?[
????preprocess_text(doc)
????for?doc?in?nlp.pipe(not_null_data
,?disable=DISABLE_PIPELINES)
]
上面的代碼是如何工作的?
首先,我們?nèi)∏?10000 行數(shù)據(jù)。此數(shù)據(jù)中的目標(biāo)是名為“情緒”的列。情緒列由兩個值組成,即“正面”和“負(fù)面”,表示相應(yīng)評論的情緒。
我們用整數(shù) 1 替換值“正”,用整數(shù) 0 替換值“負(fù)”。
我們只取非空的行,這意味著我們忽略了具有空值的評論。在獲得非空評論后,我們應(yīng)用上面定義的初始預(yù)處理函數(shù)。
方法初始預(yù)處理后的步驟是,
刪除 HTML 標(biāo)簽,如 ,并提取標(biāo)簽內(nèi)定義的數(shù)據(jù)
刪除數(shù)據(jù)中的表情符號
刪除數(shù)據(jù)中的編號模式,如 1st、2nd、3rd 等。
刪除單詞中的多余字符。例如,單詞 ohhh 被替換為 ohh。
在應(yīng)用初始預(yù)處理步驟后,我們使用 spacy 來預(yù)處理數(shù)據(jù)。預(yù)處理方法遵循的步驟是,
刪除數(shù)據(jù)中的空格。
刪除數(shù)據(jù)中的電子郵件。
刪除數(shù)據(jù)中的停用詞。
刪除數(shù)據(jù)中的 URL。
刪除數(shù)據(jù)中的標(biāo)點(diǎn)符號。
刪除數(shù)據(jù)中的數(shù)字。
詞形還原。
函數(shù) nlp.pipe 將在 spaCy 中生成一系列 doc 對象。spaCy 中的文檔是一系列令牌對象。我們使用禁用管道來加快預(yù)處理時間。
詞形還原是尋找詞根的過程。例如,單詞 running 的詞根是 run。進(jìn)行詞形還原的目的是減少詞匯量。為了使單詞詞形還原,我們使用了 nltk 包中的 WordNetLemmatizer。
tokenizer?=?Tokenizer(
????filters=FILTERS,
????lower=True
)
padding?=?'post'
tokenizer.fit_on_texts(texts)
vocab_size?=?len(tokenizer.word_index)?+?1
sequences?=?[]
max_sequence_len?=?0
for?text?in?texts:
????#?convert?texts?to?sequence
????txt_to_seq?=?tokenizer.texts_to_sequences([text])[0]
????sequences.append(txt_to_seq)
????#?find?max_sequence_len?for?padding
????txt_to_seq_len?=?len(txt_to_seq)
????if?txt_to_seq_len?>?max_sequence_len:
????????max_sequence_len?=?txt_to_seq_len
#?post?padding
padded_sequences?=?pad_sequences(
????sequences,?
????maxlen=max_sequence_len,?
????padding=padding
)
執(zhí)行預(yù)處理后,我們將對數(shù)據(jù)進(jìn)行標(biāo)記化,將標(biāo)記化的單詞轉(zhuǎn)換為序列,并填充標(biāo)記化的句子。標(biāo)記化是將句子分解為單詞序列的過程。
例如,“我喜歡蘋果”可以標(biāo)記為 [“我”,“喜歡”,“蘋果”]。將標(biāo)記化的句子轉(zhuǎn)換為序列看起來像 [1, 2, 3]。單詞“i”、“l(fā)ike”和“apples”被映射到數(shù)字 1、2 和 3。然后填充序列看起來像 [1, 2, 3, 0, 0, 0]。數(shù)字 3 后面的三個零是填充序列。這也稱為后填充。
model?=?Sequential()
model.add(Embedding(vocab_size,?64,?input_length=max_sequence_len-1))
model.add(Bidirectional(LSTM(64,?return_sequences=True,?input_shape=(None,?1))))
model.add(Dropout(0.2))
model.add(Bidirectional(LSTM(32)))
model.add(Dropout(0.2))
model.add(Dense(64,?activation='relu'))
model.add(Dropout(0.1))
model.add(Dense(1,?activation='sigmoid'))
adam?=?Adam(learning_rate=0.01)
model.compile(
????loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),?
????optimizer=adam,?
????metrics=['accuracy']
)
model.summary()

這里我們使用了使用 TensorFlow 的雙向 LSTM 模型。讓我們深入了解模型的工作原理。
首先,我們定義了一個嵌入層。嵌入層將單詞轉(zhuǎn)換為詞向量。例如,單詞“apple”可以嵌入為 [0.2, 0.12, 0.45]。維數(shù)是一個超參數(shù)。
使用詞嵌入的目的是在詞之間找到更好的相似性,這是獨(dú)熱編碼失敗的地方。這里我們選擇了維度64。
我們在這里使用的模型是堆疊的雙向 LSTM。第一個雙向?qū)佣x為 64 個單元,第二層定義為 32 個雙向 LSTM 單元。
之后,我們使用了具有 64 個單元的 Dense 層和激活函數(shù) ReLU。最后一層是具有 sigmoid 激活函數(shù)的輸出層,因?yàn)槲覀兊膯栴}是一個二元分類問題,我們使用了 sigmoid 函數(shù)。我們還使用了 Dropout 層來防止過度擬合。
我們使用 Adam 優(yōu)化函數(shù)進(jìn)行反向傳播,并使用二元交叉熵?fù)p失函數(shù)進(jìn)行度量的損失和準(zhǔn)確性。損失函數(shù)用于優(yōu)化模型,而度量用于我們的比較。要了解有關(guān) LSTM 工作的更多信息,請參閱此博客:https://colah.github.io/posts/2015-08-Understanding-LSTMs/
history?=?model.fit(
????padded_sequences,?
????labels.values,?
????epochs=10,
????verbose=1,
????batch_size=64
)
現(xiàn)在是時候訓(xùn)練模型了。我們使用了 10 個 epoch 和 64 的批量來訓(xùn)練。我們使用評論的填充序列作為特征,將情感作為目標(biāo)。

import?matplotlib.pyplot?as?plt
fig?=?plt.plot(history.history['accuracy'])
title?=?plt.title("History")
xlabel?=?plt.xlabel("Epochs")
ylabel?=?plt.ylabel("Accuracy")

如果我們繪制歷史記錄,我們可以清楚地看到,隨著epoch的增加,我們的準(zhǔn)確性也會提高。我們獲得了 99.82% 的準(zhǔn)確率。
現(xiàn)在我們已經(jīng)訓(xùn)練了我們的模型,我們可以用它來進(jìn)行預(yù)測。
predictions?=?model.predict(padded_sequences[:4])
for?pred?in?predictions:
????print(pred[0])
我們使用了前四篇經(jīng)過預(yù)處理和預(yù)測的評論。我們正在獲得以下結(jié)果。
Output
0.99986255
0.9999008
0.99985176
0.00030466914
輸出表示積極情緒的概率。讓我們檢查一下這是否正確。

這些預(yù)測非常令人印象深刻。通過這種方式,你可以利用 TensorFlow 進(jìn)行情感分析。
總結(jié)
在這篇文章中,我們了解了基于規(guī)則的情感分析和自動情感分析之間的區(qū)別。此外,我們利用深度學(xué)習(xí)的自動化情感分析來分析情感。
使用 spaCy 預(yù)處理數(shù)據(jù)。使用標(biāo)記器將文本轉(zhuǎn)換為序列。
使用堆疊雙向 LSTM 訓(xùn)練數(shù)據(jù)
訓(xùn)練后繪制歷史
使用經(jīng)過訓(xùn)練的模型進(jìn)行預(yù)測
隨意調(diào)整模型的超參數(shù),例如更改優(yōu)化器函數(shù)、添加額外層、更改激活函數(shù),并嘗試增加嵌入向量中的維度。這樣,你將能夠獲得更精細(xì),更精細(xì)的結(jié)果。
往期精彩回顧 本站qq群554839127,加入微信群請掃碼:
