利用Python機器學習框架scikit-learn,我們自己做一個分類模型,對中文評論資訊做情感分析。其中還會介紹中文停用詞的處理方法。
疑惑
前些日子,我在微信後臺收到了一則讀者的留言。
我一下子有些懵——這怎麼還帶點播了呢?
但是旋即我醒悟過來,好像是我自己之前挖了個坑。
之前我寫過《 如何用Python從海量文字抽取主題? 》一文,其中有這麼一段:
為了演示的流暢,我們這裡忽略了許多細節。很多內容使用的是預置預設引數,而且完全忽略了中文停用詞設定環節,因此“這個”、“如果”、“可能”、“就是”這樣的停用詞才會大搖大擺地出現在結果中。不過沒有關係,完成比完美重要得多。知道了問題所在,後面改進起來很容易。有機會我會寫文章介紹如何加入中文停用詞的去除環節。
根據“自己挖坑自己填”的法則,我決定把這一部分寫出來。
我可以使用偷懶的辦法。
例如在原先的教程裡,更新中文停用詞處理部分,打個補丁。
但是,最近我發現,好像至今為止,我們的教程從來沒有介紹過如何用機器學習做情感分析。
你可能說,不對吧?
情感分析不是講過了嗎?老師你好像講過《 如何用Python做情感分析? 》,《 如何用Python做輿情時間序列視覺化? 》和《 如何用Python和R對《權力的遊戲》故事情節做情緒分析? 》。
你記得真清楚,提出表揚。
但是請注意,之前這幾篇文章中,並沒有使用機器學習方法。我們只不過呼叫了第三方提供的文字情感分析工具而已。
但是問題來了,這些第三方工具是在別的資料集上面訓練出來的,未必適合你的應用場景。
例如有些情感分析工具更適合分析新聞,有的更善於處理微博資料……你拿過來,卻是要對店鋪評論資訊做分析。
這就如同你自己膝上型電腦裡的網頁瀏覽器,和圖書館電子閱覽室的網頁瀏覽器,可能型別、版本完全一樣。但是你用起自己的瀏覽器,就是比公用電腦上的舒服、高效——因為你已經根據偏好,對自己瀏覽器上的“書籤”、“密碼儲存”、“稍後閱讀”都做了個性化設定。
我們們這篇文章,就給你講講如何利用Python和機器學習,自己訓練模型,對中文評論資料做情感分類。
# 資料
我的一個學生,利用爬蟲抓取了大眾點評網站上的數萬條餐廳評論資料。
這些資料在爬取時,包含了豐富的後設資料型別。
我從中抽取了評論文字和評星(1-5星),用於本文的演示。
從這些資料裡,我們隨機篩選評星為1,2,4,5的,各500條評論資料。一共2000條。
為什麼只甩下評星數量為3的沒有選擇?
你先思考10秒鐘,然後往下看,核對答案。
答案是這樣的:
因為我們只希望對情感做出(正和負)二元分類,4和5星可以看作正向情感,1和2是負向情感……3怎麼算?
所以,為了避免這種邊界不清晰造成的混淆,我們們只好把標為3星的內容丟棄掉了。
整理好之後的評論資料,如下圖所示。
我已經把資料放到了演示資料夾壓縮包裡面。後文會給你提供下載路徑。
模型
使用機器學習的時候,你會遇到模型的選擇問題。
例如,許多模型都可以用來處理分類問題。邏輯迴歸、決策樹、SVM、樸素貝葉斯……具體到我們們的評論資訊情感分類問題,該用哪一種呢?
幸好,Python上的機器學習工具包 scikit-learn 不僅給我們提供了方便的介面,供我們呼叫,而且還非常貼心地幫我們做了小抄(cheat-sheet)。
這張圖看似密密麻麻,非常混亂,實際上是一個非常好的迷宮指南。其中綠色的方框,是各種機器學習模型。而藍色的圓圈,是你做判斷的地方。
你看,我們們要處理類別問題,對吧?
順著往下看,會要求你判斷資料是否有標記。我們有啊。
繼續往下走,資料小於100K嗎?
考慮一下,我們的資料有2000條,小於這個閾值。
接下來問是不是文字資料?是啊。
於是路徑到了終點。
Scikit-learn告訴我們:用樸素貝葉斯模型好了。
小抄都做得如此照顧使用者需求,你對scikit-learn的品質應該有個預期了吧?如果你需要使用經典機器學習模型(你可以理解成深度學習之外的所有模型),我推薦你先嚐試scikit-learn 。
向量化
《 如何用Python從海量文字抽取主題? 》一文裡,我們講過自然語言處理時的向量化。
忘了?
沒關係。
子曰:
學而時習之,不亦樂乎?
這裡我們們複習一下。
對自然語言文字做向量化(vectorization)的主要原因,是計算機看不懂自然語言。
計算機,顧名思義,就是用來算數的。文字對於它(至少到今天)沒有真正的意義。
但是自然語言的處理,是一個重要問題,也需要自動化的支援。因此人就得想辦法,讓機器能儘量理解和表示人類的語言。
假如這裡有兩句話:
I love the game.
I hate the game.
那麼我們就可以簡單粗暴地抽取出以下特徵(其實就是把所有的單詞都羅列一遍):
- I
- love
- hate
- the
- game
對每一句話,都分別計算特徵出現個數。於是上面兩句話就轉換為以下表格:
按照句子為單位,從左到右讀數字,第一句表示為[1, 1, 0, 1, 1],第二句就成了[1, 0, 1, 1, 1]。
這就叫向量化。
這個例子裡面,特徵的數量叫做維度。於是向量化之後的這兩句話,都有5個維度。
你一定要記住,此時機器依然不能理解兩句話的具體含義。但是它已經儘量在用一種有意義的方式來表達它們。
注意這裡我們使用的,叫做“一袋子詞”(bag of words)模型。
下面這張圖(來自 ~https://goo.gl/2jJ9Kp~ ),形象化表示出這個模型的含義。
一袋子詞模型不考慮詞語的出現順序,也不考慮詞語和前後詞語之間的連線。每個詞都被當作一個獨立的特徵來看待。你可能會問:“這樣不是很不精確嗎?充分考慮順序和上下文聯絡,不是更好嗎?”
沒錯,你對文字的順序、結構考慮得越周全,模型可以獲得的資訊就越多。
但是,凡事都有成本。只需要用基礎的排列組合知識,你就能計算出獨立考慮單詞,和考慮連續n個詞語(稱作 n-gram),造成的模型維度差異了。
為了簡單起見,我們們這裡還是先用一袋子詞吧。有空我再給你講講……
打住,不能再挖坑了。
中文
上一節我們們介紹的,是自然語言向量化處理的通則。
處理中文的時候,要更加麻煩一些。
因為不同於英文、法文等拉丁語系文字,中文天然沒有空格作為詞語之間的分割符號。
我們要先將中文分割成空格連線的詞語。
例如把:
“我喜歡這個遊戲”
變成:
“我 喜歡 這個 遊戲”
這樣一來,就可以仿照英文句子的向量化,來做中文的向量化了。
你可能擔心計算機處理起中文的詞語,跟處理英文詞語有所不同。
這種擔心沒必要。
因為我們們前面講過,計算機其實連英文單詞也看不懂。
在它眼裡,不論什麼自然語言的詞彙,都只是某種特定組合的字串而已。 不論處理中文還是英文,都需要處理的一種詞彙,叫做停用詞。
中文維基百科裡,是這麼定義停用詞的:
在資訊檢索中,為節省儲存空間和提高搜尋效率,在處理自然語言資料(或文字)之前或之後會自動過濾掉某些字或詞,這些字或詞即被稱為Stop Words(停用詞)。
我們們做的,不是資訊檢索,而已文字分類。
對我們們來說,你不打算拿它做特徵的單詞,就可以當作停用詞。
還是舉剛才英文的例子,下面兩句話:
I love the game.
I hate the game.
告訴我,哪些是停用詞?
直覺會告訴你,定冠詞 the 應該是。
沒錯,它是虛詞,沒有什麼特殊意義。
它在哪兒出現,都是一個意思。
一段文字裡,出現很多次定冠詞都很正常。把它和那些包含資訊更豐富的詞彙(例如love, hate)放在一起統計,就容易干擾我們把握文字的特徵。
所以,我們們把它當作停用詞,從特徵裡面剔除出去。
舉一反三,你會發現分詞後的中文語句:
“我 喜歡 這個 遊戲”
其中的“這個”應該也是停用詞吧?
答對了!
要處理停用詞,怎麼辦呢?當然你可以一個個手工來尋找,但是那顯然效率太低。
有的機構或者團隊處理過許多停用詞。他們會發現,某種語言裡,停用詞是有規律的。
他們把常見的停用詞總結出來,彙整合表格。以後只需要查表格,做處理,就可以利用先前的經驗和知識,提升效率,節約時間。
在scikit-learn中,英語停用詞是自帶的。只需要指定語言為英文,機器會幫助你自動處理它們。
但是中文……
scikit-learn開發團隊裡,大概缺少足夠多的中文使用者吧。
好訊息是,你可以使用第三方共享的停用詞表。
這種停用詞表到哪裡下載呢?
我已經幫你找到了 一個 github 專案 ,裡面包含了4種停用詞表,來自哈工大、四川大學和百度等自然語言處理方面的權威單位。
這幾個停用詞表檔案長度不同,內容也差異很大。為了演示的方便與一致性,我們們統一先用哈工大這個停用詞表吧。
我已經將其一併儲存到了演示目錄壓縮包中,供你下載。 # 環境 請你先到 這個網址 下載本教程配套的壓縮包。
下載後解壓,你會在生成的目錄裡面看到以下4個檔案。
下文中,我們會把這個目錄稱為“演示目錄”。
請一定注意記好它的位置哦。
要裝Python,最簡便辦法是安裝Anaconda套裝。
請到 這個網址 下載Anaconda的最新版本。
請選擇左側的 Python 3.6 版本下載安裝。
如果你需要具體的步驟指導,或者想知道Windows平臺如何安裝並執行Anaconda命令,請參考我為你準備的 視訊教程 。
開啟終端,用cd命令進入演示目錄。如果你不瞭解具體使用方法,也可以參考 視訊教程 。 我們需要使用許多軟體包。如果每一個都手動安裝,會非常麻煩。
我幫你做了個虛擬環境的配置檔案,叫做environment.yaml ,也放在演示目錄中。
請你首先執行以下命令:
conda env create -f environment.yaml
這樣,所需的軟體包就一次性安裝完畢了。
之後執行,
source activate datapy3
進入這個虛擬環境。
注意一定要執行下面這句:
python -m ipykernel install --user --name=datapy3
只有這樣,當前的Python環境才會作為核心(kernel)在系統中註冊。 確認你的電腦上已經安裝了 Google Chrome 瀏覽器。如果沒有安裝請到這裡 下載 安裝。
之後,在演示目錄中,我們執行:
jupyter notebook
Google Chrome會開啟,並啟動 Jupyter 筆記本介面:
你可以直接點選檔案列表中的demo.ipynb檔案,可以看到本教程的全部示例程式碼。
你可以一邊看教程的講解,一邊依次執行這些程式碼。
但是,我建議的方法,是回到主介面下,新建一個新的空白 Python 3 (顯示名稱為datapy3的那個)筆記本。
請跟著教程,一個個字元輸入相應的內容。這可以幫助你更為深刻地理解程式碼的含義,更高效地把技能內化。
準備工作結束,下面我們開始正式輸入程式碼。
程式碼
我們讀入資料框處理工具pandas。
import pandas as pd
複製程式碼
利用pandas的csv讀取功能,把資料讀入。
注意為了與Excel和系統環境設定的相容性,該csv資料檔案採用的編碼為GB18030。這裡需要顯式指定,否則會報錯。
df = pd.read_csv('data.csv', encoding='gb18030')
複製程式碼
我們看看讀入是否正確。
df.head()
複製程式碼
前5行內容如下:
看看資料框整體的形狀是怎麼樣的:
df.shape
複製程式碼
(2000, 2)
複製程式碼
我們的資料一共2000行,2列。完整讀入。
我們並不準備把情感分析的結果分成4個類別。我們只打算分成正向和負向。
這裡我們用一個無名函式來把評星數量>3的,當成正向情感,取值為1;反之視作負向情感,取值為0。
def make_label(df):
df["sentiment"] = df["star"].apply(lambda x: 1 if x>3 else 0)
複製程式碼
編制好函式之後,我們實際執行在資料框上面。
make_label(df)
複製程式碼
看看結果:
df.head()
複製程式碼
從前5行看來,情感取值就是根據我們設定的規則,從評星數量轉化而來。
下面我們把特徵和標籤拆開。
X = df[['comment']]
y = df.sentiment
複製程式碼
X 是我們的全部特徵。因為我們只用文字判斷情感,所以X實際上只有1列。
X.shape
複製程式碼
(2000, 1)
複製程式碼
而y是對應的標記資料。它也是隻有1列。
y.shape
複製程式碼
(2000,)
複製程式碼
我們來看看 X 的前幾行資料。
X.head()
複製程式碼
注意這裡評論資料還是原始資訊。詞語沒有進行拆分。
為了做特徵向量化,下面我們利用結巴分詞工具來拆分句子為詞語。
import jieba
複製程式碼
我們建立一個輔助函式,把結巴分詞的結果用空格連線。
這樣分詞後的結果就如同一個英文句子一樣,單次之間依靠空格分割。
def chinese_word_cut(mytext):
return " ".join(jieba.cut(mytext))
複製程式碼
有了這個函式,我們就可以使用 apply 命令,把每一行的評論資料都進行分詞。
X['cutted_comment'] = X.comment.apply(chinese_word_cut)
複製程式碼
我們看看分詞後的效果:
X.cutted_comment[:5]
複製程式碼
單詞和標點之間都用空格分割,符合我們的要求。
下面就是機器學習的常規步驟了:我們需要把資料分成訓練集和測試集。
為什麼要拆分資料集合?
在《貸還是不貸:如何用Python和機器學習幫你決策?》一文中,我已解釋過,這裡複習一下:
如果期末考試之前,老師給你一套試題和答案,你把它背了下來。然後考試的時候,只是從那套試題裡面抽取一部分考。你憑藉超人的記憶力獲得了100分。請問你學會了這門課的知識了嗎?不知道如果給你新的題目,你會不會做呢?答案還是不知道。所以考試題目需要和複習題目有區別。
同樣的道理,假設我們們的模型只在某個資料集上訓練,準確度非常高,但是從來沒有見過其他新資料,那麼它面對新資料表現如何呢?
你心裡也沒底吧?
所以我們需要把資料集拆開,只在訓練集上訓練。保留測試集先不用,作為考試題,看模型經過訓練後的分類效果。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
複製程式碼
這裡,我們設定了 random_state
取值,這是為了在不同環境中,保證隨機數取值一致,以便驗證我們們模型的實際效果。
我們看看此時的 X_train
資料集形狀。
X_train.shape
複製程式碼
(1500, 2)
複製程式碼
可見,在預設模式下,train_test_split
函式對訓練集和測試集的劃分比例為 3:1。
我們檢驗一下其他3個集合看看:
y_train.shape
複製程式碼
(1500,)
複製程式碼
X_test.shape
複製程式碼
(500, 2)
複製程式碼
y_test.shape
複製程式碼
(500,)
複製程式碼
同樣都正確無誤。
下面我們就要處理中文停用詞了。
我們編寫一個函式,從中文停用詞表裡面,把停用詞作為列表格式儲存並返回:
def get_custom_stopwords(stop_words_file):
with open(stop_words_file) as f:
stopwords = f.read()
stopwords_list = stopwords.split('\n')
custom_stopwords_list = [i for i in stopwords_list]
return custom_stopwords_list
複製程式碼
我們指定使用的停用詞表,為我們已經下載儲存好的哈工大停用詞表檔案。
stop_words_file = "stopwordsHIT.txt"
stopwords = get_custom_stopwords(stop_words_file)
複製程式碼
看看我們的停用詞列表的後10項:
stopwords[-10:]
複製程式碼
這些大部分都是語氣助詞,作為停用詞去除掉,不會影響到語句的實質含義。
下面我們就要嘗試對分詞後的中文語句做向量化了。
我們讀入CountVectorizer
向量化工具,它依據詞語出現頻率轉化向量。
from sklearn.feature_extraction.text import CountVectorizer
複製程式碼
我們建立一個CountVectorizer()
的例項,起名叫做vect。
注意這裡為了說明停用詞的作用。我們先使用預設引數建立vect。
vect = CountVectorizer()
複製程式碼
然後我們用向量化工具轉換已經分詞的訓練集語句,並且將其轉化為一個資料框,起名為term_matrix
。
term_matrix = pd.DataFrame(vect.fit_transform(X_train.cutted_comment).toarray(), columns=vect.get_feature_names())
複製程式碼
我們看看term_matrix
的前5行:
term_matrix.head()
複製程式碼
我們注意到,特徵詞語五花八門,特別是很多數字都被當作特徵放在了這裡。
term_matrix
的形狀如下:
term_matrix.shape
複製程式碼
(1500, 7305)
複製程式碼
行數沒錯,列數就是特徵個數,有7305個。
下面我們測試一下,加上停用詞去除功能,特徵向量的轉化結果會有什麼變化。
vect = CountVectorizer(stop_words=frozenset(stopwords))
複製程式碼
下面的語句跟剛才一樣:
term_matrix = pd.DataFrame(vect.fit_transform(X_train.cutted_comment).toarray(), columns=vect.get_feature_names())
複製程式碼
term_matrix.head()
複製程式碼
可以看到,此時特徵個數從剛才的7305個,降低為7144個。我們沒有調整任何其他的引數,因此減少的161個特徵,就是出現在停用詞表中的單詞。
但是,這種停用詞表的寫法,依然會漏掉不少漏網之魚。
首先就是前面那一堆顯眼的數字。它們在此處作為特徵毫無道理。如果沒有單位,沒有上下文,數字都是沒有意義的。
因此我們需要設定,數字不能作為特徵。
在Python裡面,我們可以設定token_pattern
來完成這個目標。
這一部分需要用到正規表示式的知識,我們這裡無法詳細展開了。
但如果你只是需要去掉數字作為特徵的話,按照我這樣寫,就可以了。
另一個問題在於,我們看到這個矩陣,實際上是個非常稀疏的矩陣,其中大部分的取值都是0.
這沒有關係,也很正常。
畢竟大部分評論語句當中只有幾個到幾十個詞語而已。7000多的特徵,單個語句顯然是覆蓋不過來的。
然而,有些詞彙作為特徵,就值得注意了。
首先是那些過於普遍的詞彙。儘管我們用了停用詞表,但是難免有些詞彙幾乎出現在每一句評論裡。什麼叫做特徵?特徵就是可以把一個事物與其他事物區別開的屬性。
假設讓你描述今天見到的印象最深刻的人。你怎麼描述?
我看見他穿著小丑的衣服,在繁華的商業街踩高蹺,一邊走還一邊拋球,和路人打招呼。
還是……
我看見他有兩隻眼睛,一隻鼻子。
後者絕對不算是好的特徵描述,因為難以把你要描述的個體區分出來。
物極必反,那些過於特殊的詞彙,其實也不應該保留。因為你瞭解了這個特徵之後,對你的模型處理新的語句情感判斷,幾乎都用不上。
這就如同你跟著神仙學了屠龍之術,然而之後一輩子也沒有見過龍……
所以,如下面兩個程式碼段所示,我們一共多設定了3層特徵詞彙過濾。
max_df = 0.8 # 在超過這一比例的文件中出現的關鍵詞(過於平凡),去除掉。
min_df = 3 # 在低於這一數量的文件中出現的關鍵詞(過於獨特),去除掉。
複製程式碼
vect = CountVectorizer(max_df = max_df,
min_df = min_df,
token_pattern=u'(?u)\\b[^\\d\\W]\\w+\\b',
stop_words=frozenset(stopwords))
複製程式碼
這時候,再執行我們之前的語句,看看效果。
term_matrix = pd.DataFrame(vect.fit_transform(X_train.cutted_comment).toarray(), columns=vect.get_feature_names())
複製程式碼
term_matrix.head()
複製程式碼
可以看到,那些數字全都不見了。特徵數量從單一詞表法去除停用詞之後的7144個,變成了1864個。
你可能會覺得,太可惜了吧?好容易分出來的詞,就這麼扔了?
要知道,特徵多,絕不一定是好事兒。
尤其是噪聲大量混入時,會顯著影響你模型的效能。
好了,評論資料訓練集已經特徵向量化了。下面我們要利用生成的特徵矩陣來訓練模型了。
我們的分類模型,採用樸素貝葉斯(Multinomial naive bayes)。
from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB()
複製程式碼
注意我們的資料處理流程是這樣的:
- 特徵向量化;
- 樸素貝葉斯分類。
如果每次修改一個引數,或者換用測試集,我們都需要重新執行這麼多的函式,肯定是一件效率不高,且令人頭疼的事兒。而且只要一複雜,出現錯誤的機率就會增加。
幸好,Scikit-learn給我們提供了一個功能,叫做管道(pipeline),可以方便解決這個問題。
它可以幫助我們,把這些順序工作連線起來,隱藏其中的功能順序關聯,從外部一次呼叫,就能完成順序定義的全部工作。
使用很簡單,我們就把 vect 和 nb 串聯起來,叫做pipe。
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(vect, nb)
複製程式碼
看看它都包含什麼步驟:
pipe.steps
複製程式碼
看,我們剛才做的工作,都在管道里面了。我們可以把管道當成一個整體模型來呼叫。
下面一行語句,就可以把未經特徵向量化的訓練集內容輸入,做交叉驗證,算出模型分類準確率的均值。
from sklearn.cross_validation import cross_val_score
cross_val_score(pipe, X_train.cutted_comment, y_train, cv=5, scoring='accuracy').mean()
複製程式碼
我們們的模型在訓練中的準確率如何呢?
0.820687244673089
複製程式碼
這個結果,還是不錯的。
回憶一下,總體的正向和負向情感,各佔了資料集的一半。
如果我們建立一個“笨模型”(dummy model),即所有的評論,都當成正向(或者負向)情感,準確率多少?
對,50%。
目前的模型準確率,遠遠超出這個數值。超出的這30%多,其實就是評論資訊為模型帶來的確定性。
但是,不要忘了,我們不能光拿訓練集來說事兒,對吧?下面我們們給模型來個考試。
我們用訓練集,把模型擬合出來。
pipe.fit(X_train.cutted_comment, y_train)
複製程式碼
然後,我們在測試集上,對情感分類標記進行預測。
pipe.predict(X_test.cutted_comment)
複製程式碼
這一大串0和1,你看得是否眼花繚亂?
沒關係,scikit-learn給我們提供了非常多的模型效能測度工具。
我們先把預測結果儲存到y_pred
。
y_pred = pipe.predict(X_test.cutted_comment)
複製程式碼
讀入 scikit-learn 的測量工具集。
from sklearn import metrics
複製程式碼
我們先來看看測試準確率:
metrics.accuracy_score(y_test, y_pred)
複製程式碼
0.86
複製程式碼
這個結果是不是讓你很吃驚?沒錯,模型面對沒有見到的資料,居然有如此高的情感分類準確性。
對於分類問題,光看準確率有些不全面,我們們來看看混淆矩陣。
metrics.confusion_matrix(y_test, y_pred)
複製程式碼
array([[194, 43],
[ 27, 236]])
複製程式碼
混淆矩陣中的4個數字,分別代表:
- TP: 本來是正向,預測也是正向的;
- FP: 本來是負向,預測卻是正向的;
- FN: 本來是正向,預測卻是負向的;
- TN: 本來是負向,預測也是負向的。
下面這張圖(來自 https://goo.gl/5cYGZd )應該能讓你更為清晰理解混淆矩陣的含義:
寫到這兒,你大概能明白我們們模型的效能了。
但是總不能只把我們們訓練出的模型和無腦“笨模型”去對比吧?這也太不公平了!
下面,我們把老朋友 SnowNLP 呼喚出來,做個對比。
如果你把它給忘了,請複習《如何用Python做情感分析?》
from snownlp import SnowNLP
def get_sentiment(text):
return SnowNLP(text).sentiments
複製程式碼
我們利用測試集評論原始資料,讓 SnowNLP 跑一遍,獲得結果。
y_pred_snownlp = X_test.comment.apply(get_sentiment)
複製程式碼
注意這裡有個小問題。 SnowNLP 生成的結果,不是0和1,而是0到1之間的小數。所以我們需要做一步轉換,把0.5以上的結果當作正向,其餘當作負向。
y_pred_snownlp_normalized = y_pred_snownlp.apply(lambda x: 1 if x>0.5 else 0)
複製程式碼
看看轉換後的前5條 SnowNLP 預測結果:
y_pred_snownlp_normalized[:5]
複製程式碼
好了,符合我們的要求。
下面我們先看模型分類準確率:
metrics.accuracy_score(y_test, y_pred_snownlp_normalized)
複製程式碼
0.77
複製程式碼
與之對比,我們們的測試集分類準確率,可是0.86哦。
我們再來看看混淆矩陣。
metrics.confusion_matrix(y_test, y_pred_snownlp_normalized)
複製程式碼
array([[189, 48],
[ 67, 196]])
複製程式碼
對比的結果,是 TP 和 TN 兩項上,我們們的模型判斷正確數量,都要超出 SnowNLP。
小結
回顧一下,本文介紹了以下知識點:
- 如何用一袋子詞(bag of words)模型將自然語言語句向量化,形成特徵矩陣;
- 如何利用停用詞表、詞頻閾值和標記模式(token pattern)移除不想幹的偽特徵詞彙,降低模型複雜度。
- 如何選用合適的機器學習分類模型,對詞語特徵矩陣做出分類;
- 如何用管道模式,歸併和簡化機器學習步驟流程;
- 如何選擇合適的效能測度工具,對模型的效能進行評估和對比。
希望這些內容能夠幫助你更高效地處理中文文字情感分類工作。
討論
你之前用機器學習做過中文情感分類專案嗎?你是如何去除停用詞的?你使用的分類模型是哪個?獲得的準確率怎麼樣?歡迎留言,把你的經驗和思考分享給大家,我們一起交流討論。
喜歡請點贊。還可以微信關注和置頂我的公眾號“玉樹芝蘭”(nkwangshuyi)。
如果你對資料科學感興趣,不妨閱讀我的系列教程索引貼《如何高效入門資料科學?》,裡面還有更多的有趣問題及解法。