note1:萬(wàn)分抱歉夷陋,由于期末降臨欠拾,在插入代碼時(shí)筆者表現(xiàn)較為倉(cāng)促胰锌,對(duì)空格/tab的處理不到位,還請(qǐng)各位看官實(shí)操時(shí)手動(dòng)調(diào)整藐窄。
note2:若行文有疏漏资昧,還請(qǐng)各位留言指正,蟹蟹荆忍。
chapter1 引言
在本章中,將對(duì)文本數(shù)據(jù)進(jìn)行情感分析格带。情感分析(或意見挖掘)這一術(shù)語(yǔ)指的是從主體對(duì)特定主題的態(tài)度方面分析數(shù)據(jù)。這種態(tài)度可以是基于心理評(píng)估理論的判斷刹枉、情感,態(tài)或刻意的情感交流叽唱。
一般地,情感分析是基于自然語(yǔ)言處理、文本分析和計(jì)算語(yǔ)言學(xué)來(lái)完成的微宝。雖然數(shù)據(jù)來(lái)自不同的數(shù)據(jù)源,但在本章中,將用兩個(gè)特定的文本數(shù)據(jù)示例來(lái)分析在文本數(shù)據(jù)中的情緒:一個(gè)示例來(lái)自電影評(píng)論家,其文本高度結(jié)構(gòu)化并有語(yǔ)義信息;另一個(gè)示例來(lái)自社交網(wǎng)絡(luò)[本例中是推文(twitter) ],其文本無(wú)結(jié)構(gòu)且用戶可能使用(甚至濫用! )文本縮寫棺亭。
在接下來(lái)的章節(jié)中,將回顧進(jìn)行情感分析所需的一些基本途徑。詳細(xì)地說(shuō),將分析數(shù)據(jù)清理所需的步驟(即刪除與情感信息無(wú)關(guān)的文本項(xiàng)),產(chǎn)生文本的一般表示,并在文本表示上進(jìn)行一些統(tǒng)計(jì)推斷以確定積極的和消極的情緒蟋软。
盡管情感分析的范圍可能會(huì)引入許多需要分析的方面,但在本章中,為簡(jiǎn)單起見,將分析二元情感分析的分類問題镶摘。因此,我們基本上要學(xué)會(huì)從文本數(shù)據(jù)中分類出肯定觀點(diǎn)和否定觀點(diǎn)。情感分析的范圍是廣泛的,包括很多方面,這使情感分析成為一項(xiàng)具有挑戰(zhàn)性的任務(wù)岳守。本主題中一些有趣的公開性問題如下:
諷刺的識(shí)別:有時(shí)不知道人的性格,不知道“壞”是指壞的還是好的凄敢。
沒有文本結(jié)構(gòu):以推文為例,它可能包含縮寫,可能沒有大寫、拼寫錯(cuò)誤湿痢、標(biāo)點(diǎn),號(hào)錯(cuò)誤贡未、語(yǔ)法錯(cuò)誤,所有的這些都使得分析文本困難。
許多可能的情感類別和程度:積極和消極是一個(gè)簡(jiǎn)單的分析,我們想要確定的是D心有多少討厭的意見蒙袍、多少快樂的意見、多少悲傷的意見等嫩挤。
確定分析的對(duì)象:文本中可以出現(xiàn)很多概念,如何察覺意見是積極的還是消極的是個(gè)公開的問題害幅。例如,若你說(shuō)“她贏了他! ",那么這對(duì)她來(lái)說(shuō)意味著積極的情緒,同時(shí)對(duì)他來(lái)說(shuō)意味著消極的情感。
主觀的文本:另一個(gè)公開的挑戰(zhàn)是如何分析非常主觀的句子或段落岂昭。有時(shí),即使對(duì)人類來(lái)說(shuō),也很難就這些高度主觀文本的觀點(diǎn)達(dá)成一致以现。
chapter2 數(shù)據(jù)清洗
為了進(jìn)行情感分析,首先需要討論數(shù)據(jù)的一些處理步驟。接下來(lái),將在多個(gè)簡(jiǎn)單的句子上應(yīng)用不同的步驟,來(lái)更好地理解每一個(gè)句子约啊。之后,將在更大的數(shù)據(jù)集上執(zhí)行整個(gè)程序邑遏。
給定單元格[1]中的輸入文本數(shù)據(jù),數(shù)據(jù)清洗的主要任務(wù)是刪除那些在數(shù)據(jù)挖掘過(guò)程中被認(rèn)為是噪聲的字符。例如,逗號(hào)或冒號(hào)字符恰矩。當(dāng)然,在每個(gè)特定的數(shù)據(jù)挖掘問題中,取決于分析的最終目的,不同的字符可以被視為噪聲记盒。在本例中,將考慮刪除所有標(biāo)點(diǎn)字符,包括其他非常規(guī)符號(hào)。為了執(zhí)行數(shù)據(jù)清洗流程和后面的文本表示與分析,將在本章中使用自然語(yǔ)言工具箱( Natural Language Toolkit, NLTK )庫(kù)作為例子外傅。
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可以容易地將字符串形式的文檔轉(zhuǎn)換為詞向量,這個(gè)過(guò)程被稱為分詞俩檬。看一下下面的例子碾盟。
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', '.']]
因此,對(duì)于在raw_docs中的每一行文本, word_tokenize函數(shù)將建立詞向量的列表棚辽。例如,現(xiàn)在可以搜索標(biāo)點(diǎn)符號(hào)的列表,然后刪除它們。有很多方法可以完成這一步冰肴。面看看使用String庫(kù)的一個(gè)可能方案屈藐。
import string
string.
result:
'!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~'
可以看到string.punctuation包含一組常用的標(biāo)點(diǎn)符號(hào)。這個(gè)列表可以根據(jù)想除的符號(hào)進(jìn)行修改熙尉。下面看看使用正則表達(dá)式( Regular Expression, RE )包的下一個(gè)示例如何刪除標(biāo)點(diǎn)符號(hào)的联逻。請(qǐng)注意,有許多其他可能的方法來(lái)刪除存在的符號(hào),如直接執(zhí)行位置比較的循環(huán)。
在輸入單元格[4]中, re.compile包含一個(gè)“表達(dá)式”列表, “表達(dá)式”為stringpunctuation中包含的符號(hào)骡尽。這里,不打算深入地討論RE的細(xì)節(jié)遣妥。
然后,在tokenized-docs中的每一項(xiàng)都與regex中包含的表達(dá)式/符號(hào)進(jìn)行匹配每項(xiàng)對(duì)應(yīng)于標(biāo)點(diǎn)符號(hào)的部分被u"替代(這里u指的是unicode編碼),如果替換后的項(xiàng))應(yīng)的是u",則該項(xiàng)不被列入到最終列表中。如果新項(xiàng)與u"不同,則意味著該項(xiàng)包含標(biāo)點(diǎn)符號(hào)之外的文本,因此它被列入到不包含標(biāo)點(diǎn)符號(hào)的新列表tokenized_docsnopunctuation中攀细。使用此腳本的結(jié)果顯示在輸出單元格[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’]]
可以看到,標(biāo)點(diǎn)符號(hào)被刪除,且含有標(biāo)點(diǎn)符號(hào)的那些詞被保留并被初始的u標(biāo)記。如果讀者想要了解更多的細(xì)節(jié),建議閱讀有關(guān)用于處理表達(dá)式的RE包的信息谭贪。
在許多用于文本分析的數(shù)據(jù)挖掘系統(tǒng)中,另一個(gè)重要步驟是詞干分析和詞匯歸并境钟。詞法學(xué)中有詞具有根形式的概念。如果想要了解該詞的基本術(shù)語(yǔ)含義,可以嘗試使用詞干分析器或詞匯歸并器俭识。這一步有助于減少大小,降低后驗(yàn)高維(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’]]
這種方法對(duì)減少具有相同含義的字詞組合的指數(shù)數(shù)目及匹配相似文本是十分有用的。如“興趣”和“有趣”這樣的詞將被轉(zhuǎn)換成相同的詞-“興趣”,從而使文本的比較更容易套媚,這將在后面看到缚态。
另一個(gè)非常有用的數(shù)據(jù)清洗步驟是HTML實(shí)體及標(biāo)簽的刪除。這些可能包含文字和其他符號(hào)堤瘤,這些文字和符號(hào)使用之前的步驟無(wú)法被刪除玫芦,而且它們不能為文本分析提供有用
的語(yǔ)義,并將在后面的文本表示程序中引人噪聲。有許多可能的方法可以用來(lái)刪除這些標(biāo)簽本辐,這里給出了另一個(gè)同樣使用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>"的標(biāo)簽已被刪除。讀者可以參考RE包的文檔來(lái)了解更多關(guān)于如何使用它來(lái)進(jìn)行數(shù)據(jù)清洗和進(jìn)行HTML解析以移除標(biāo)簽的信息慎皱。
chapter3 文本表示
在之前的章節(jié)中,分析了不同的技術(shù),有數(shù)據(jù)清洗老虫、詞干分析和詞匯歸并;還對(duì)文本進(jìn)行了篩選,來(lái)刪除其他在后文分析中不必要的標(biāo)簽。為了分析源自文本的情感,下一步是要得到已清理的文本表示茫多。雖然存在不同的文本表示,但最常見的是詞袋( Bag of Words Bow)模型的變體祈匙。其基本思想是考慮詞頻。如果能定義一個(gè)可能有不同詞的詞典,不同的現(xiàn)有詞數(shù)量將被定義成特征空間的長(zhǎng)度,用來(lái)表示每個(gè)文本地梨。
參見下圖[10.1]的簡(jiǎn)單示例菊卷。兩種不同的文本代表了在這種情況下所有可用的文本缔恳。這個(gè)詞典中不同字詞的總數(shù)是7,它表示特征向量的長(zhǎng)度。然后,可以通過(guò)使用詞頻,以特征向量的方式來(lái)表示兩個(gè)可用文本中的任意一個(gè),如下圖所示洁闰。最后兩行代表詞典中每個(gè)文本構(gòu)成的特征向量歉甚。
接下來(lái),將查看一個(gè)特殊的Bow,即文本的向量空間模型(vector space model ):
TF-IDF (term frequency-inverse document frequency,詞頻-逆文檔頻率),首先,需要對(duì)每個(gè)文檔的詞條即詞頻向量計(jì)數(shù)。請(qǐng)參閱下面的代碼示例:
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)]
這里,引入了一個(gè)名為Counter的Python對(duì)象扑眉。Counter只存在于Python 2.7及更高版本中纸泄。它很有用,因?yàn)樗试S你執(zhí)行這種確切類型的功能:在循環(huán)中計(jì)數(shù)。Counter是用于計(jì)數(shù)可哈希對(duì)象的字典子類腰素。它是一個(gè)無(wú)序的集合,元素被存儲(chǔ)為字典的關(guān)鍵字,它們的計(jì)數(shù)被存儲(chǔ)為字典的值聘裁。計(jì)數(shù)可以是任何整數(shù)值,包括零或負(fù)數(shù)。
元素從一個(gè)迭代中計(jì)數(shù)或從另一個(gè)映射(或Counter)初始化弓千。
c = Counter() # a new , empty counter
c = Counter(’gallahad’) # a new counter from an iterable
counter對(duì)象有一個(gè)字典接口,它返回一個(gè)值為零的計(jì)數(shù)來(lái)表示缺失項(xiàng),而不是拋出KeyError 異常衡便。
c = Counter([ ’eggs’, ’ham’])
c [’bacon’]
result:
0
我們定量表示文檔的第一步僅僅是求出它們的字?jǐn)?shù)統(tǒng)計(jì)(也可以認(rèn)為是使用了以前的方法來(lái)過(guò)濾和清洗文本)。這里,給出一個(gè)基于詞頻來(lái)計(jì)算特征向量的例子洋访。
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]]
現(xiàn)在,每篇文檔都在相同的特征空間中,這意味著可以在同一個(gè)維度空間中表示整個(gè)語(yǔ)料庫(kù)镣陕。一旦有了在相同特征空間中的數(shù)據(jù),就可以開始應(yīng)用一些機(jī)器學(xué)習(xí)方法:學(xué)習(xí)、分類姻政、聚類等呆抑。但實(shí)際上,還有一些問題。字詞并不都是等信息量的汁展。如果字詞在單個(gè)文檔中出現(xiàn)的頻率過(guò)高,它們將會(huì)破壞分析鹊碍。我們想要對(duì)這些詞頻向量進(jìn)行一些加權(quán),使其中一些更有代表性。也就是說(shuō),需要做一些向量歸一化食绿。一種可能性是確保每個(gè)向量的L2范數(shù)等于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
- 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. - 0.40824829 0.40824829 0.40824829]]
可以看到已經(jīng)縮減了向量,使得每個(gè)元素在[0,1]之間侈咕。這將避免在特定文檔中,被大時(shí)使用的字詞的信息價(jià)值出現(xiàn)收益遞減的情況。為此,需要縮減在文檔中過(guò)于頻繁出現(xiàn)的洞器紧。
最后,有一個(gè)終極任務(wù)要完成乎完。就像并非所有字詞在文檔中具有同等價(jià)值一樣,并非所有蘭詞在所有文檔中都是有價(jià)值的∑仿澹可以嘗試通過(guò)其逆文檔頻率來(lái)重新加權(quán)每個(gè)字詞。
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]
現(xiàn)在我們對(duì)詞表中的每個(gè)詞的信息價(jià)值有了一個(gè)總體的了解,說(shuō)明了它們?cè)谡麄€(gè)語(yǔ))庫(kù)中的相對(duì)頻率摩桶。請(qǐng)注意,這是一個(gè)逆向計(jì)算桥状。為了得到TF-IDF加權(quán)的字詞向量,必須)行詞頻乘以逆頻率值的簡(jiǎn)單計(jì)算。
在下一個(gè)例子中,將IDF向量轉(zhuǎn)換成矩陣,矩陣的對(duì)角線即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. ]]
這意味著現(xiàn)在可以將每個(gè)詞頻向量乘以逆文檔頻率矩陣辅斟。那么為了確保對(duì)在文檔中頻繁出現(xiàn)的字詞做出解釋,將使用L2規(guī)范來(lái)歸一化每個(gè)文檔。
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.
- ]
[ 0.52812101 0. 0.2640605 0. 0.2640605 0.2640605 0.71547492 0.
- ]
- ]
[ 0. 0.56467328 0. 0.56467328 0.20840411 0. 0. 0. 0.56467328 0.
- ]
- ]]
10.3.1 二元組和n元組
使用Bow將重要的二元組引入到模型中有時(shí)是有用的芦拿。請(qǐng)注意,這個(gè)例子可以擴(kuò)展到 n元組士飒。在計(jì)算語(yǔ)言學(xué)和概率論領(lǐng)域中查邢,n元組是來(lái)自給定文本或語(yǔ)音序列的n項(xiàng)連續(xù)序列。這些項(xiàng)可以是音素/音節(jié)/字母/字詞等酵幕。n元組通常從文本或語(yǔ)音語(yǔ)料庫(kù)中收集扰藕。
大小為1的n元組稱為"一元組(uni-gram) "。大小為2則是一個(gè)"二元組(bigram)" [或不太常見地稱為連字(digram)];大小為3則是一個(gè)“三元組(tri-gram)"芳撒。較大規(guī)格的元組有時(shí)用n值來(lái)表示,如“四元組” “五元組”等邓深。這些n元組可以在Bow的模型中引入,只需將每個(gè)不同的n元組作為特征向量表示式中的新位置即可笔刹。
chapter4 實(shí)際案例
Python包為文本的分析提供了有用的工具芥备。讀者可以參考NLTK和Texblb包的文檔來(lái)了解更多細(xì)節(jié)。在這里,將執(zhí)行所有以前出現(xiàn)的舌菜、用于數(shù)據(jù)清理萌壳、詞干分析和表達(dá)的程序,并引入一些二元學(xué)習(xí)方案來(lái)學(xué)習(xí)特征空間中的文本表示。二元學(xué)習(xí)方案將接收用于訓(xùn)練積極情緒和消極情緒的文本示例,稍后將其應(yīng)用到來(lái)自測(cè)試集的未見過(guò)的示例中日月。
我們將把整個(gè)情感分析過(guò)程用到兩個(gè)示例中袱瓮。第一個(gè)對(duì)應(yīng)大電影評(píng)論數(shù)據(jù)集"。這是用于情感分析的最大公共可用數(shù)據(jù)集之一,其包含超過(guò)50000個(gè)電影評(píng)論的文本,包括與正面和負(fù)面電影評(píng)論相關(guān)的注釋山孔。作為概念證明,對(duì)于這個(gè)示例,使用由大約30%的數(shù)據(jù)組成的數(shù)據(jù)集的一個(gè)子集懂讯。
代碼重用了以前數(shù)據(jù)清洗示例的一部分,即從數(shù)據(jù)集作者提供的文件夾中讀取訓(xùn)練和測(cè)試數(shù)據(jù)。然后,計(jì)算TF-IDF,執(zhí)行之前提到的台颠、用于計(jì)算特征空間褐望、歸一化和特征權(quán)重的所有步驟。請(qǐng)注意,在腳本的最后,將基于兩種不同的最先進(jìn)的機(jī)器學(xué)習(xí)方法進(jìn)行訓(xùn)練和測(cè)試:樸素貝葉斯( naive Bayes )和支持向量機(jī)(suport ector machine, SM)法和參數(shù)的細(xì)節(jié)超出了本章的范圍串前。這里,重要的一點(diǎn)是在可以被不同數(shù)據(jù)挖掘工具使用的特征空間中表示文檔瘫里。
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 模塊提供的機(jī)器學(xué)習(xí)工具外, NLTK也提供了用于文本學(xué)習(xí)的有用學(xué)習(xí)工具,其中還包括樸素貝葉斯分類器。另一個(gè)具有相似功能的相關(guān)包是Texblob荡碾。接下來(lái)會(huì)顯示運(yùn)行腳本的結(jié)果:
: 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
可以看到,樸素貝葉斯對(duì)被選定數(shù)據(jù)的訓(xùn)練誤差是129/4313,而在測(cè)試中它是2087/6292,有趣的是,使用SVM的訓(xùn)練誤差更高( 1288/4313 ),但它在測(cè)試集上提供了比樸素貝葉斯更好的泛化性能( 1680/6292),因此,似乎樸素貝葉斯會(huì)生成更多的過(guò)擬合數(shù)據(jù)(選取特定的特征來(lái)更好地學(xué)習(xí)訓(xùn)練數(shù)據(jù),但是對(duì)無(wú)法修復(fù)的測(cè)試產(chǎn)生如此多的特征空間修改,降低了該技術(shù)的泛化能力),但是請(qǐng)注意,在提供的數(shù)據(jù)集的一個(gè)子集上,這是標(biāo)準(zhǔn)方法的一個(gè)簡(jiǎn)單的執(zhí)行過(guò)程谨读。更多的數(shù)據(jù)以及其他許多方面都會(huì)影響性能。例如,可以通過(guò)引入早已研究過(guò)的積極和消極字詞來(lái)豐富詞典(如在http://www.cs.uic.edu/-liub/BS/sentiment-analysis.html中提供的那些)坛吁。關(guān)于這個(gè)數(shù)據(jù)集分析的更多細(xì)節(jié),見參考文獻(xiàn)劳殖。
最后,看看另一個(gè)基于推文的情感分析示例。雖然有一些工作使用了更多的推文數(shù)據(jù),但在這里只展示了一組縮減的推文,這些推文如前面電影評(píng)論的示例一樣被分析拨脉。除了初始數(shù)據(jù)的定義外,主代碼保持不變哆姻。
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
在這種情況下,兩種學(xué)習(xí)策略在訓(xùn)練集和測(cè)試集上都達(dá)到了相同的識(shí)別率。請(qǐng)注意,相似的字詞是在推文之間共享的玫膀。實(shí)際上,在真實(shí)的例子中,推文將包括非結(jié)構(gòu)化的句子和縮寫,這會(huì)使識(shí)別更加困難矛缨。
chapter5 小結(jié)
在本章中,分析了文本數(shù)據(jù)的二元情感分析問題:用數(shù)據(jù)清洗來(lái)刪除不相關(guān)的符號(hào)、標(biāo)點(diǎn)和標(biāo)簽;詞干分析為在句子中表示相同意思的不同字詞定義了相同的根;定義了詞典(包括m元組);根據(jù)詞典的長(zhǎng)度用特征空間表示文本。在這個(gè)特征空間中,也看到了基于歸一化和加權(quán)詞頻的編碼箕昭。已經(jīng)定義了任何機(jī)器學(xué)習(xí)技術(shù)都可以使用的特征向量來(lái)完成情感分析(在示例中展示的二元分類),并且回顧了一些有用的灵妨、用于情感分析的Python包,如NLTK和Textblob。
正如本章引言所討論的那樣,僅僅回顧了情感分析問題,并介紹了完成由二元分類問題引起的分析的一般步驟落竹。一些公開性的問題可以在進(jìn)一步的研究中得到解決泌霍。僅舉幾例如諷刺的識(shí)別、無(wú)文本結(jié)構(gòu)(如推文)筋量、許多可能的情感類別和程度(不僅是二元,還有多元烹吵、回歸和多標(biāo)簽問題等)、分析對(duì)象的辨識(shí)和主觀文本等桨武。
本章所講述的工具可以為處理那些更具挑戰(zhàn)性的問題提供一個(gè)基礎(chǔ)肋拔。當(dāng)前最前沿研究的一個(gè)近期示例是參考文獻(xiàn)[3]的工作,即將深度學(xué)習(xí)架構(gòu)用于情感分析。深度學(xué)習(xí)目前是模式識(shí)別呀酸、機(jī)器學(xué)習(xí)和計(jì)算機(jī)視覺等領(lǐng)域的強(qiáng)大工具;主要的深度學(xué)習(xí)策略是基于神經(jīng)網(wǎng)絡(luò)架構(gòu)的凉蜂。在參考文獻(xiàn)[3]中,深度學(xué)習(xí)模型根據(jù)句子結(jié)構(gòu)建立了整個(gè)句子的表示,并且根據(jù)字詞如何構(gòu)成更長(zhǎng)短語(yǔ)的含義來(lái)計(jì)算出情感。在本章解釋的方法中, n元組是捕獲這些語(yǔ)義的唯一特征性誉。關(guān)于這個(gè)領(lǐng)域的進(jìn)一步討論,見參考文獻(xiàn)[4, 5].
參考文獻(xiàn)
- 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).
- 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.
- 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).
- 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)
- B. Pang, L. Lee, Opinion mining and sentiment analysis. Found Trends Inf. Retr. 2( 1-2),1 (2008)