用於情感分析的統計自然語言處理

本文代碼修改自:~~
英文原版見~~

note1:萬分抱歉,由於期末降臨,在插入代碼時筆者表現較爲倉促,對空格/tab的處理不到位,還請各位看官實操時手動調整。
note2:若行文有疏漏,還請各位留言指正,蟹蟹。

chapter1 引言

在本章中,將對文本數據進行情感分析。情感分析(或意見挖掘)這一術語指的是從主體對特定主題的態度方面分析數據。這種態度可以是基於心理評估理論的判斷、情感,態或刻意的情感交流。

一般地,情感分析是基於自然語言處理、文本分析和計算語言學來完成的。雖然數據來自不同的數據源,但在本章中,將用兩個特定的文本數據示例來分析在文本數據中的情緒:一個示例來自電影評論家,其文本高度結構化並有語義信息;另一個示例來自社交網絡[本例中是推文(twitter) ],其文本無結構且用戶可能使用(甚至濫用! )文本縮寫。

在接下來的章節中,將回顧進行情感分析所需的一些基本途徑。詳細地說,將分析數據清理所需的步驟(即刪除與情感信息無關的文本項),產生文本的一般表示,並在文本表示上進行一些統計推斷以確定積極的和消極的情緒。

儘管情感分析的範圍可能會引入許多需要分析的方面,但在本章中,爲簡單起見,將分析二元情感分析的分類問題。因此,我們基本上要學會從文本數據中分類出肯定觀點和否定觀點。情感分析的範圍是廣泛的,包括很多方面,這使情感分析成爲一項具有挑戰性的任務。本主題中一些有趣的公開性問題如下:

  1. 諷刺的識別:有時不知道人的性格,不知道“壞”是指壞的還是好的。

  2. 沒有文本結構:以推文爲例,它可能包含縮寫,可能沒有大寫、拼寫錯誤、標點,號錯誤、語法錯誤,所有的這些都使得分析文本困難。

  3. 許多可能的情感類別和程度:積極和消極是一個簡單的分析,我們想要確定的是D心有多少討厭的意見、多少快樂的意見、多少悲傷的意見等。

  4. 確定分析的對象:文本中可以出現很多概念,如何察覺意見是積極的還是消極的是個公開的問題。例如,若你說“她贏了他! ",那麼這對她來說意味着積極的情緒,同時對他來說意味着消極的情感。

  5. 主觀的文本:另一個公開的挑戰是如何分析非常主觀的句子或段落。有時,即使對人類來說,也很難就這些高度主觀文本的觀點達成一致。

chapter2 數據清洗

爲了進行情感分析,首先需要討論數據的一些處理步驟。接下來,將在多個簡單的句子上應用不同的步驟,來更好地理解每一個句子。之後,將在更大的數據集上執行整個程序。

給定單元格[1]中的輸入文本數據,數據清洗的主要任務是刪除那些在數據挖掘過程中被認爲是噪聲的字符。例如,逗號或冒號字符。當然,在每個特定的數據挖掘問題中,取決於分析的最終目的,不同的字符可以被視爲噪聲。在本例中,將考慮刪除所有標點字符,包括其他非常規符號。爲了執行數據清洗流程和後面的文本表示與分析,將在本章中使用自然語言工具箱( Natural Language Toolkit, NLTK )庫作爲例子。

raw_docs = ["Here are some very simple basic sentences.", "They won't be very interesting, I'm afraid.", "The point of these examples is to _learn how basic text cleaning works_ on *very simple* data."]

第一步包括定義包含文本中所有詞向量的列表。NLTK可以容易地將字符串形式的文檔轉換爲詞向量,這個過程被稱爲分詞。看一下下面的例子。

from nltk.tokenize import word_tokenize
tokenized_docs = [word_tokenize(doc) for doc in raw_docs]
print tokenized_docs

result:
[['Here', 'are', 'some', 'very', 'simple', 'basic', 'sentences', '.'], ['They', 'wo', "n't", 'be', 'very', 'interesting', ',', 'I', "'m", 'afraid', '.'],
['The', 'point', 'of', 'these', 'examples', 'is', 'to', 'learn', 'how', 'basic', 'text', 'cleaning', 'works', 'on', 'very', 'simple', 'data', '.']]

因此,對於在raw_docs中的每一行文本, word_tokenize函數將建立詞向量的列表。例如,現在可以搜索標點符號的列表,然後刪除它們。有很多方法可以完成這一步。面看看使用String庫的一個可能方案。

import string
string.

result:
'!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~'

可以看到string.punctuation包含一組常用的標點符號。這個列表可以根據想除的符號進行修改。下面看看使用正則表達式( Regular Expression, RE )包的下一個示例如何刪除標點符號的。請注意,有許多其他可能的方法來刪除存在的符號,如直接執行位置比較的循環。

在輸入單元格[4]中, re.compile包含一個“表達式”列表, “表達式”爲stringpunctuation中包含的符號。這裏,不打算深入地討論RE的細節。

然後,在tokenized-docs中的每一項都與regex中包含的表達式/符號進行匹配每項對應於標點符號的部分被u"替代(這裏u指的是unicode編碼),如果替換後的項)應的是u",則該項不被列入到最終列表中。如果新項與u"不同,則意味着該項包含標點符號之外的文本,因此它被列入到不包含標點符號的新列表tokenized_docsnopunctuation中。使用此腳本的結果顯示在輸出單元格[4]中。

import re
import string
regex = re.compile('[%s]' % re.escape(string.punctuation))
tokenized_docs_no_punctuation = []
for review in tokenized_docs:
    new_review = []
    for token in review:
        new_token = regex.sub(u'', token)
        if not new_token == u'':
            new_review.append(new_token)
    tokenized_docs_no_punctuation.append(new_review)
print tokenized_docs_no_punctuation

result:
[[’Here’, ’are’, ’some’, ’very’, ’simple’, ’basic’,
’sentences’],
[’They’, ’wo’, u’nt’, ’be’, ’very’, ’interesting’, ’I’, u’m’,
’afraid’],
[’The’, ’point’, ’of’, ’these’, ’examples’, ’is’, ’to’,
u’learn’, ’how’, ’basic’, ’text’, ’cleaning’, u’works’, ’on’,
u’very’, u’simple’, ’data’]]

可以看到,標點符號被刪除,且含有標點符號的那些詞被保留並被初始的u標記。如果讀者想要了解更多的細節,建議閱讀有關用於處理表達式的RE包的信息。

在許多用於文本分析的數據挖掘系統中,另一個重要步驟是詞幹分析和詞彙歸併。詞法學中有詞具有根形式的概念。如果想要了解該詞的基本術語含義,可以嘗試使用詞幹分析器或詞彙歸併器。這一步有助於減少大小,降低後驗高維(posterior high-dimensional)和減少稀疏特徵空間( sparse feature space ), NLTK提供了完成此步驟的不同方式。在使用porter. stem (word)方法的情況下,輸出如下所示:

import re
import string
regex = re.compile('[%s]' % re.escape(string.punctuation))
tokenized_docs_no_punctuation = []
for review in tokenized_docs:
    new_review = []
    for token in review:
        new_token = regex.sub(u'', token)
        if not new_token == u'':
            new_review.append(new_token)
    tokenized_docs_no_punctuation.append(new_review)
print(tokenized_docs_no_punctuation)

result:
[[’Here’, ’are’, ’some’, ’very’, ’simple’, ’basic’,
’sentences’], [’They’, ’wo’, u’nt’, ’be’, ’very’,
’interesting’, ’I’, u’m’, ’afraid’], [’The’, ’point’, ’of’,
’these’, ’examples’, ’is’, ’to’, u’learn’, ’how’, ’basic’,
’text’, ’cleaning’, u’works’, ’on’, u’very’, u’simple’,
’data’]]
[[’Here’, ’are’, ’some’, ’veri’, ’simpl’, ’basic’, ’sentenc’],
[’They’, ’wo’, u’nt’, ’be’, ’veri’, ’interest’, ’I’, u’m’,
’afraid’], [’The’, ’point’,’of’, ’these’, ’exampl’, ’is’,
’to’, u’learn’, ’how’, ’basic’, ’text’, ’clean’, u’work’, ’on’,
u’veri’,u’simpl’, ’data’]]
這種方法對減少具有相同含義的字詞組合的指數數目及匹配相似文本是十分有用的。如“興趣”和“有趣”這樣的詞將被轉換成相同的詞-“興趣”,從而使文本的比較更容易,這將在後面看到。

另一個非常有用的數據清洗步驟是HTML實體及標籤的刪除。這些可能包含文字和其他符號,這些文字和符號使用之前的步驟無法被刪除,而且它們不能爲文本分析提供有用
的語義,並將在後面的文本表示程序中引人噪聲。有許多可能的方法可以用來刪除這些標籤,這裏給出了另一個同樣使用NLTK包的示例。

import nltk
test_string ="<p>While many of the stories tugged
at the heartstrings , I never felt manipulated by
the authors. ( Note: Part of the reason why I
don’t like the ’Chicken Soup for the Soul’
series is that I feel that the authors are just
dying to make the reader clutch for the box of
tissues .) </a>"
print ’Original text:’
print test_string
print ’Cleaned text:’
nltk. clean_html(test_string. decode())

result:
Original text:
<p>While many of the stories tugged at the heartstrings, I
never felt manipulated by the authors. (Note: Part of the
reason why I don’t like the "Chicken Soup for the Soul" series
is that I feel that the authors are just dying to make the
reader clutch for the box of tissues.)</a>
Cleaned text:
u"While many of the stories tugged at the heartstrings, I never
felt manipulated by the authors. (Note: Part of the reason why
I don’t like the "Chicken Soup for the Soul" series is that I
feel that the authors are just dying to make the reader clutch
for the box of tissues.)"

可以看到,如"(p2"和"/a>"的標籤已被刪除。讀者可以參考RE包的文檔來了解更多關於如何使用它來進行數據清洗和進行HTML解析以移除標籤的信息。

chapter3 文本表示

在之前的章節中,分析了不同的技術,有數據清洗、詞幹分析和詞彙歸併;還對文本進行了篩選,來刪除其他在後文分析中不必要的標籤。爲了分析源自文本的情感,下一步是要得到已清理的文本表示。雖然存在不同的文本表示,但最常見的是詞袋( Bag of Words Bow)模型的變體。其基本思想是考慮詞頻。如果能定義一個可能有不同詞的詞典,不同的現有詞數量將被定義成特徵空間的長度,用來表示每個文本。

參見下圖[10.1]的簡單示例。兩種不同的文本代表了在這種情況下所有可用的文本。這個詞典中不同字詞的總數是7,它表示特徵向量的長度。然後,可以通過使用詞頻,以特徵向量的方式來表示兩個可用文本中的任意一個,如下圖所示。最後兩行代表詞典中每個文本構成的特徵向量。



接下來,將查看一個特殊的Bow,即文本的向量空間模型(vector space model ):
TF-IDF (term frequency-inverse document frequency,詞頻-逆文檔頻率),首先,需要對每個文檔的詞條即詞頻向量計數。請參閱下面的代碼示例:

mydoclist = [’Mireia loves me more than Hector
loves me’,
’Sergio likes me more than Mireia loves me’,
’ He likes basketball more than football’]
from collections import Counter
for doc in mydoclist:
tf = Counter()
for word in doc.split():
tf[word] += 1
print tf.items()

result:
: [(’me’, 2), (’Mireia’, 1), (’loves’, 2), (’Hector’, 1),
(’than’, 1), (’more’, 1)] [(’me’, 2), (’Mireia’, 1), (’likes’,
1), (’loves’, 1), (’Sergio’, 1), (’than’, 1), (’more’, 1)]
[(’basketball’, 1), (’football’, 1), (’likes’, 1), (’He’, 1),
(’than’, 1), (’more’, 1)]
這裏,引入了一個名爲Counter的Python對象。Counter只存在於Python 2.7及更高版本中。它很有用,因爲它允許你執行這種確切類型的功能:在循環中計數。Counter是用於計數可哈希對象的字典子類。它是一個無序的集合,元素被存儲爲字典的關鍵字,它們的計數被存儲爲字典的值。計數可以是任何整數值,包括零或負數。
元素從一個迭代中計數或從另一個映射(或Counter)初始化。

c = Counter() # a new , empty counter
c = Counter(’gallahad’) # a new counter from an iterable

counter對象有一個字典接口,它返回一個值爲零的計數來表示缺失項,而不是拋出KeyError 異常。

c = Counter([ ’eggs’, ’ham’])
c [’bacon’]

result:
0
我們定量表示文檔的第一步僅僅是求出它們的字數統計(也可以認爲是使用了以前的方法來過濾和清洗文本)。這裏,給出一個基於詞頻來計算特徵向量的例子。

def build_lexicon( corpus):
# define a set with all possible words included in
all the sentences or "corpus"
lexicon = set()
for doc in corpus:
lexicon.update ([word for word in doc.split
()])
return lexicon
def tf(term , document):
return freq(term , document)
def freq(term , document):
return document. split().count( term)
vocabulary = build_lexicon (mydoclist)
doc_term_matrix = []
print ’Our vocabulary vector is [’ +
’, ’.join(list( vocabulary)) + ’]’
for doc in mydoclist:
print ’The doc is "’ + doc + ’"’
tf_vector = [tf(word , doc) for word in
vocabulary]
tf_vector_string = ’, ’.join(format(freq , ’d’)
for freq
in tf_vector)
print ’The tf vector for Document %d is [%s]’
% ((mydoclist. index(doc)+1),
tf_vector_string)
doc_term_matrix. append(tf_vector)
print ’All combined , here is our master document
term matrix: ’
print doc_term_matrix

result:
Our vocabulary vector is [me, basketball, Julie, baseball,
likes, loves, Jane, Linda, He, than, more]
The doc is "Julie loves me more than Linda loves me"
The tf vector for Document 1 is [2, 0, 1, 0, 0, 2, 0, 1, 0, 1,
1]
The doc is "Jane likes me more than Julie loves me"
The tf vector for Document 2 is [2, 0, 1, 0, 1, 1, 1, 0, 0, 1,
1]
The doc is "He likes basketball more than baseball"
The tf vector for Document 3 is [0, 1, 0, 1, 1, 0, 0, 0, 1, 1,
1]
All combined, here is our master document term matrix:
[[2, 0, 1, 0, 0, 2, 0, 1, 0, 1, 1], [2, 0, 1, 0, 1, 1, 1, 0, 0,
1, 1], [0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1]]
現在,每篇文檔都在相同的特徵空間中,這意味着可以在同一個維度空間中表示整個語料庫。一旦有了在相同特徵空間中的數據,就可以開始應用一些機器學習方法:學習、分類、聚類等。但實際上,還有一些問題。字詞並不都是等信息量的。如果字詞在單個文檔中出現的頻率過高,它們將會破壞分析。我們想要對這些詞頻向量進行一些加權,使其中一些更有代表性。也就是說,需要做一些向量歸一化。一種可能性是確保每個向量的L2範數等於1.

import math
def l2_normalizer(vec):
denom = np.sum([el**2 for el in vec])
return [(el / math.sqrt(denom)) for el in vec]
doc_term_matrix_l2 = []
for vec in doc_term_matrix:
doc_term_matrix_l2. append( l2_normalizer(vec))
print ’A regular old document term matrix: ’
print np.matrix (doc_term_matrix)
print ’\nA document term matrix with row -wise L2
norm:’
print np.matrix( doc_term_matrix_l2)

result:
: A regular old document term matrix:
[[2 0 1 0 0 2 0 1 0 1 1]
[2 0 1 0 1 1 1 0 0 1 1]
[0 1 0 1 1 0 0 0 1 1 1]]
A document term matrix with row-wise L2 norm:
[[ 0.57735027 0. 0.28867513 0. 0. 0.57735027

  1. 0.28867513 0. 0.28867513 0.28867513]
    [ 0.63245553 0. 0.31622777 0. 0.31622777 0.31622777
    0.31622777 0. 0. 0.31622777 0.31622777]
    [ 0. 0.40824829 0. 0.40824829 0.40824829 0. 0.
  2. 0.40824829 0.40824829 0.40824829]]
    可以看到已經縮減了向量,使得每個元素在[0,1]之間。這將避免在特定文檔中,被大時使用的字詞的信息價值出現收益遞減的情況。爲此,需要縮減在文檔中過於頻繁出現的洞。

最後,有一個終極任務要完成。就像並非所有字詞在文檔中具有同等價值一樣,並非所有蘭詞在所有文檔中都是有價值的。可以嘗試通過其逆文檔頻率來重新加權每個字詞。

def numDocsContaining(word , doclist):
doccount = 0
for doc in doclist:
if freq(word , doc) > 0:
doccount += 1
return doccount
def idf(word , doclist):
n_samples = len(doclist)
df = numDocsContaining(word , doclist)
return np.log(n_samples / (float(df)) )
my_idf_vector = [idf(word , mydoclist) for word in
vocabulary]
print ’Our vocabulary vector is [’ + ’, ’.join(list
(vocabulary)) + ’]’
print ’The inverse document frequency vector is
[ ’ + ’, ’.join(format(freq , ’f’) for freq in
my_idf_vector) + ’]’

result:
Our vocabulary vector is [me, basketball, Mireia, football,
likes, loves, Sergio, Hector, He, than, more]
The inverse document frequency vector is [0.405465, 1.098612,
0.405465, 1.098612, 0.405465, 0.405465, 1.098612, 1.098612,
1.098612, 0.000000, 0.000000]
現在我們對詞表中的每個詞的信息價值有了一個總體的瞭解,說明了它們在整個語)庫中的相對頻率。請注意,這是一個逆向計算。爲了得到TF-IDF加權的字詞向量,必須)行詞頻乘以逆頻率值的簡單計算。

在下一個例子中,將IDF向量轉換成矩陣,矩陣的對角線即IDF向量。

def build_idf_matrix( idf_vector):
idf_mat = np.zeros((len(idf_vector), len(
idf_vector)))
np.fill_diagonal( idf_mat , idf_vector)
return idf_mat
my_idf_matrix = build_idf_matrix (my_idf_vector)
print my_idf_matrix

result:
[[ 0.40546511 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 1.09861229 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0.40546511 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 1.09861229 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0.40546511 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0.40546511 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 1.09861229 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 1.09861229 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 1.09861229 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. ]]
這意味着現在可以將每個詞頻向量乘以逆文檔頻率矩陣。那麼爲了確保對在文檔中頻繁出現的字詞做出解釋,將使用L2規範來歸一化每個文檔。

doc_term_matrix_tfidf = []
#performing tf -idf matrix multiplication
for tf_vector in doc_term_matrix:
doc_term_matrix_tfidf. append(np.dot(tf_vector ,
my_idf_matrix))
#normalizing
doc_term_matrix_tfidf_l2 = []
for tf_vector in doc_term_matrix_tfidf:
doc_term_matrix_tfidf_l2.
append( l2_normalizer(tf_vector))
print vocabulary
# np.matrix() just to make it easier to look at
print np.matrix( doc_term_matrix_tfidf_l2)

result:
set([’me’, ’basketball’, ’Mireia’, ’football’, ’likes’,
’loves’, ’Sergio’, ’Linda’, ’He’, ’than’, ’more’])
[[ 0.49474872 0. 0.24737436 0. 0. 0.49474872 0. 0.67026363 0.

    1. ]
      [ 0.52812101 0. 0.2640605 0. 0.2640605 0.2640605 0.71547492 0.
      1. ]
        [ 0. 0.56467328 0. 0.56467328 0.20840411 0. 0. 0. 0.56467328 0.
  1. ]]

10.3.1 二元組和n元組

使用Bow將重要的二元組引入到模型中有時是有用的。請注意,這個例子可以擴展到 n元組。在計算語言學和概率論領域中,n元組是來自給定文本或語音序列的n項連續序列。這些項可以是音素/音節/字母/字詞等。n元組通常從文本或語音語料庫中收集。

大小爲1的n元組稱爲"一元組(uni-gram) "。大小爲2則是一個"二元組(bigram)" [或不太常見地稱爲連字(digram)];大小爲3則是一個“三元組(tri-gram)"。較大規格的元組有時用n值來表示,如“四元組” “五元組”等。這些n元組可以在Bow的模型中引入,只需將每個不同的n元組作爲特徵向量表示式中的新位置即可。

chapter4 實際案例

Python包爲文本的分析提供了有用的工具。讀者可以參考NLTK和Texblb包的文檔來了解更多細節。在這裏,將執行所有以前出現的、用於數據清理、詞幹分析和表達的程序,並引入一些二元學習方案來學習特徵空間中的文本表示。二元學習方案將接收用於訓練積極情緒和消極情緒的文本示例,稍後將其應用到來自測試集的未見過的示例中。

我們將把整個情感分析過程用到兩個示例中。第一個對應大電影評論數據集"。這是用於情感分析的最大公共可用數據集之一,其包含超過50000個電影評論的文本,包括與正面和負面電影評論相關的註釋。作爲概念證明,對於這個示例,使用由大約30%的數據組成的數據集的一個子集。

代碼重用了以前數據清洗示例的一部分,即從數據集作者提供的文件夾中讀取訓練和測試數據。然後,計算TF-IDF,執行之前提到的、用於計算特徵空間、歸一化和特徵權重的所有步驟。請注意,在腳本的最後,將基於兩種不同的最先進的機器學習方法進行訓練和測試:樸素貝葉斯( naive Bayes )和支持向量機(suport ector machine, SM)法和參數的細節超出了本章的範圍。這裏,重要的一點是在可以被不同數據挖掘工具使用的特徵空間中表示文檔。

from nltk. tokenize import word_tokenize
from nltk.stem .porter import PorterStemmer
from sklearn. feature_extraction. text import
TfidfVectorizer
from nltk. classify import NaiveBayesClassifier
from sklearn. naive_bayes import GaussianNB
from sklearn import svm
from unidecode import unidecode
def BoW(text):
# Tokenizing text
text_tokenized = [word_tokenize(doc) for doc in
text]
# Removing punctuation
regex = re.compile(’[%s]’ % re.escape(string.
punctuation))
tokenized_docs_no_punctuation = []
for review in text_tokenized:
new_review = []
for token in review:
new_token = regex.sub(u’ ’, token)
if not new_token == u’ ’:
new_review. append(new_token)
tokenized_docs_no_punctuation. append(
new_review)
# Stemming and Lemmatizing
porter = PorterStemmer()
preprocessed_docs = []
for doc in tokenized_docs_no_punctuation:
final_doc = ’ ’
for word in doc:
final_doc = final_doc + ’ ’ + porter.
stem(word)
preprocessed_docs. append(final_doc)
return preprocessed_docs
#read your train text data here
textTrain= ReadTrainDataText()
preprocessed_docs=BoW(textTrain) # for train data
# Computing TIDF word space
tfidf_vectorizer = TfidfVectorizer( min_df = 1)
trainData = tfidf_vectorizer.fit_transform(
preprocessed_docs)
textTest= ReadTestDataText() #read your test text
data here
prepro_docs_test=BoW(textTest) # for test data
testData = tfidf_vectorizer. transform(
prepro_docs_test)
print (’Training and testing on training Naive Bayes
’)
gnb = GaussianNB()
testData.todense()
y_pred = gnb.fit(trainData.todense() , targetTrain)
.predict(trainData.todense())
print ("Number of mislabeled training points out of
a total %d points : %d"
% (trainData. shape[0],( targetTrain != y_pred)
.sum()))
y_pred = gnb.fit(trainData.todense() , targetTrain)
.predict(testData.todense())
print ("Number of mislabeled test points out of a
total %d points : %d" %
(testData. shape[0],( targetTest != y_pred).sum
()))
print (’Training and testing on train with SVM’)
clf = svm.SVC()
clf.fit(trainData. todense(), targetTrain)
y_pred = clf.predict( trainData.todense())
print ("Number of mislabeled test points out of a
total %d points : %d" %
(trainData. shape[0],( targetTrain != y_pred).
sum()))
print (’Testing on test with already trained SVM’)
y_pred = clf.predict(testData.todense())
print ("Number of mislabeled test points out of a
total %d points : %d" %
(testData. shape[0],( targetTest != y_pred).sum
()))

除了本示例中使用的Sciki-learn 模塊提供的機器學習工具外, NLTK也提供了用於文本學習的有用學習工具,其中還包括樸素貝葉斯分類器。另一個具有相似功能的相關包是Texblob。接下來會顯示運行腳本的結果:
: Training and testing on training Naive Bayes
Number of mislabeled training points out of a total 4313 points
: 129
Number of mislabeled test points out of a total 6292 points :
2087
Training and testing on train with SVM
Number of mislabeled test points out of a total 4313 points :
1288
Testing on test with already trained SVM
Number of mislabeled test points out of a total 6292 points :
1680
可以看到,樸素貝葉斯對被選定數據的訓練誤差是129/4313,而在測試中它是2087/6292,有趣的是,使用SVM的訓練誤差更高( 1288/4313 ),但它在測試集上提供了比樸素貝葉斯更好的泛化性能( 1680/6292),因此,似乎樸素貝葉斯會生成更多的過擬合數據(選取特定的特徵來更好地學習訓練數據,但是對無法修復的測試產生如此多的特徵空間修改,降低了該技術的泛化能力),但是請注意,在提供的數據集的一個子集上,這是標準方法的一個簡單的執行過程。更多的數據以及其他許多方面都會影響性能。例如,可以通過引入早已研究過的積極和消極字詞來豐富詞典(如在http://www.cs.uic.edu/-liub/BS/sentiment-analysis.html中提供的那些)。關於這個數據集分析的更多細節,見參考文獻。

最後,看看另一個基於推文的情感分析示例。雖然有一些工作使用了更多的推文數據,但在這裏只展示了一組縮減的推文,這些推文如前面電影評論的示例一樣被分析。除了初始數據的定義外,主代碼保持不變。

textTrain = [’I love this sandwich.’, ’This is an
amazing place!’, ’I feel very good about these
beers.’, ’This is my best work.’, ’What an
awesome view’, ’I do not like this restaurant’,
’I am tired of this stuff.’, ’I can not deal
with this’, ’He is my sworn enemy!’, ’My boss is
horrible.’]
targetTrain = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
preprocessed_docs=BoW(textTrain)
tfidf_vectorizer = TfidfVectorizer( min_df = 1)
trainData = tfidf_vectorizer.fit_transform(
preprocessed_docs)
textTest = [’The beer was good.’, ’I do not enjoy
my job’, ’I aint feeling dandy today’, ’I feel
amazing!’, ’Gary is a friend of mine.’, ’I can
not believe I am doing this.’]
targetTest = [0, 1, 1, 0, 0, 1]
preprocessed_docs=BoW(textTest)
testData = tfidf_vectorizer. transform(
preprocessed_docs)
print (’Training and testing on test Naive Bayes’)
gnb = GaussianNB()
testData.todense()
y_pred = gnb.fit(trainData.todense() , targetTrain)
.predict(trainData.todense())
print ("Number of mislabeled training points out of
a total %d points : %d" % (trainData. shape[0],(
targetTrain != y_pred).sum()))
y_pred = gnb.fit(trainData.todense() , targetTrain)
.predict(testData.todense())
print ("Number of mislabeled test points out of a
total %d points : %d" % (testData. shape[0],(
targetTest != y_pred).sum()))
print (’Training and testing on train with SVM’)
clf = svm.SVC()
clf.fit(trainData. todense(), targetTrain)
y_pred = clf.predict( trainData.todense())
print ("Number of mislabeled test points out of a
total
%d points : %d"
% (trainData. shape[0],( targetTrain != y_pred
).sum()))
print (’Testing on test with already trained SVM’)
y_pred = clf.predict(testData.todense())
print ("Number of mislabeled test points out of a
total
%d points : %d"
% (testData. shape[0],( targetTest != y_pred).
sum()))

result:
: Training and testing on test Naive Bayes
Number of mislabeled training points out of a total 10 points : 0
Number of mislabeled test points out of a total 6 points : 2
Training and testing on train with SVM
Number of mislabeled test points out of a total 10 points : 0
Testing on test with already trained SVM
Number of mislabeled test points out of a total 6 points : 2
在這種情況下,兩種學習策略在訓練集和測試集上都達到了相同的識別率。請注意,相似的字詞是在推文之間共享的。實際上,在真實的例子中,推文將包括非結構化的句子和縮寫,這會使識別更加困難。

chapter5 小結

在本章中,分析了文本數據的二元情感分析問題:用數據清洗來刪除不相關的符號、標點和標籤;詞幹分析爲在句子中表示相同意思的不同字詞定義了相同的根;定義了詞典(包括m元組);根據詞典的長度用特徵空間表示文本。在這個特徵空間中,也看到了基於歸一化和加權詞頻的編碼。已經定義了任何機器學習技術都可以使用的特徵向量來完成情感分析(在示例中展示的二元分類),並且回顧了一些有用的、用於情感分析的Python包,如NLTK和Textblob。

正如本章引言所討論的那樣,僅僅回顧了情感分析問題,並介紹了完成由二元分類問題引起的分析的一般步驟。一些公開性的問題可以在進一步的研究中得到解決。僅舉幾例如諷刺的識別、無文本結構(如推文)、許多可能的情感類別和程度(不僅是二元,還有多元、迴歸和多標籤問題等)、分析對象的辨識和主觀文本等。

本章所講述的工具可以爲處理那些更具挑戰性的問題提供一個基礎。當前最前沿研究的一個近期示例是參考文獻[3]的工作,即將深度學習架構用於情感分析。深度學習目前是模式識別、機器學習和計算機視覺等領域的強大工具;主要的深度學習策略是基於神經網絡架構的。在參考文獻[3]中,深度學習模型根據句子結構建立了整個句子的表示,並且根據字詞如何構成更長短語的含義來計算出情感。在本章解釋的方法中, n元組是捕獲這些語義的唯一特徵。關於這個領域的進一步討論,見參考文獻[4, 5].

參考文獻

  1. Z. Ren, J. Yuan. J. Meng. Z. Zhang. Robust part-based hand gesture recognition using Ki-nect sensor. IEEE Transactions on Multimedia 15 (5) , 1110-1120( 2013).
  2. A. L. Maas, R. E. Daly, P. T. Pham, D. Huang. A. Y. Ng. C. Potts, learning word vectorsfor sentiment analysis, in Proceedings of the 49th Annual Meeting of the Associationfor Computational Linguistics: Human Language Technologies (Association for Com-putational Linguistics, Portland, Oregon. USA. 2011) . pp. 142-150. URL http://www.aclweb.org/anthology/P11-1015.
  3. R. Socher, A. Perelygin, J. Wu, J. Chuang, C. Manning, A. Ng, C. Potts. Recursive deepmodels for semantic compositionality over a sentiment treebank. Conference on Empiri-cal Methods in Natural Language Processing ( 2013).
  4. E. Cambria, B. Schuller, Y. Xia, C. Havasi, New avenues in opinion mining and senti-ment analysis. IEEE Intelligent Systems 28 (2) , 15-21 (2013)
  5. B. Pang, L. Lee, Opinion mining and sentiment analysis. Found Trends Inf. Retr. 2( 1-2),1 (2008)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章