如何用Python和機器學習訓練中文文字情感分類模型?

王樹義發表於2018-06-27

利用Python機器學習框架scikit-learn,我們自己做一個分類模型,對中文評論資訊做情感分析。其中還會介紹中文停用詞的處理方法。

如何用Python和機器學習訓練中文文字情感分類模型?

疑惑

前些日子,我在微信後臺收到了一則讀者的留言。

如何用Python和機器學習訓練中文文字情感分類模型?

我一下子有些懵——這怎麼還帶點播了呢?

但是旋即我醒悟過來,好像是我自己之前挖了個坑。

之前我寫過《 如何用Python從海量文字抽取主題? 》一文,其中有這麼一段:

為了演示的流暢,我們這裡忽略了許多細節。很多內容使用的是預置預設引數,而且完全忽略了中文停用詞設定環節,因此“這個”、“如果”、“可能”、“就是”這樣的停用詞才會大搖大擺地出現在結果中。不過沒有關係,完成比完美重要得多。知道了問題所在,後面改進起來很容易。有機會我會寫文章介紹如何加入中文停用詞的去除環節。

根據“自己挖坑自己填”的法則,我決定把這一部分寫出來。

我可以使用偷懶的辦法。

例如在原先的教程裡,更新中文停用詞處理部分,打個補丁。

但是,最近我發現,好像至今為止,我們的教程從來沒有介紹過如何用機器學習做情感分析。

你可能說,不對吧?

情感分析不是講過了嗎?老師你好像講過《 如何用Python做情感分析? 》,《 如何用Python做輿情時間序列視覺化? 》和《 如何用Python和R對《權力的遊戲》故事情節做情緒分析? 》。

你記得真清楚,提出表揚。

但是請注意,之前這幾篇文章中,並沒有使用機器學習方法。我們只不過呼叫了第三方提供的文字情感分析工具而已。

但是問題來了,這些第三方工具是在別的資料集上面訓練出來的,未必適合你的應用場景。

例如有些情感分析工具更適合分析新聞,有的更善於處理微博資料……你拿過來,卻是要對店鋪評論資訊做分析。

這就如同你自己膝上型電腦裡的網頁瀏覽器,和圖書館電子閱覽室的網頁瀏覽器,可能型別、版本完全一樣。但是你用起自己的瀏覽器,就是比公用電腦上的舒服、高效——因為你已經根據偏好,對自己瀏覽器上的“書籤”、“密碼儲存”、“稍後閱讀”都做了個性化設定。

我們們這篇文章,就給你講講如何利用Python和機器學習,自己訓練模型,對中文評論資料做情感分類。

# 資料

我的一個學生,利用爬蟲抓取了大眾點評網站上的數萬條餐廳評論資料。

這些資料在爬取時,包含了豐富的後設資料型別。

我從中抽取了評論文字和評星(1-5星),用於本文的演示。

從這些資料裡,我們隨機篩選評星為1,2,4,5的,各500條評論資料。一共2000條。

為什麼只甩下評星數量為3的沒有選擇?

你先思考10秒鐘,然後往下看,核對答案。

答案是這樣的:

因為我們只希望對情感做出(正和負)二元分類,4和5星可以看作正向情感,1和2是負向情感……3怎麼算?

所以,為了避免這種邊界不清晰造成的混淆,我們們只好把標為3星的內容丟棄掉了。

整理好之後的評論資料,如下圖所示。

如何用Python和機器學習訓練中文文字情感分類模型?

我已經把資料放到了演示資料夾壓縮包裡面。後文會給你提供下載路徑。

模型

使用機器學習的時候,你會遇到模型的選擇問題。

例如,許多模型都可以用來處理分類問題。邏輯迴歸、決策樹、SVM、樸素貝葉斯……具體到我們們的評論資訊情感分類問題,該用哪一種呢?

幸好,Python上的機器學習工具包 scikit-learn 不僅給我們提供了方便的介面,供我們呼叫,而且還非常貼心地幫我們做了小抄(cheat-sheet)。

如何用Python和機器學習訓練中文文字情感分類模型?

這張圖看似密密麻麻,非常混亂,實際上是一個非常好的迷宮指南。其中綠色的方框,是各種機器學習模型。而藍色的圓圈,是你做判斷的地方。

你看,我們們要處理類別問題,對吧?

順著往下看,會要求你判斷資料是否有標記。我們有啊。

繼續往下走,資料小於100K嗎?

考慮一下,我們的資料有2000條,小於這個閾值。

接下來問是不是文字資料?是啊。

於是路徑到了終點。

Scikit-learn告訴我們:用樸素貝葉斯模型好了。

小抄都做得如此照顧使用者需求,你對scikit-learn的品質應該有個預期了吧?如果你需要使用經典機器學習模型(你可以理解成深度學習之外的所有模型),我推薦你先嚐試scikit-learn 。

向量化

如何用Python從海量文字抽取主題? 》一文裡,我們講過自然語言處理時的向量化。

忘了?

沒關係。

子曰:

學而時習之,不亦樂乎?

這裡我們們複習一下。

對自然語言文字做向量化(vectorization)的主要原因,是計算機看不懂自然語言。

計算機,顧名思義,就是用來算數的。文字對於它(至少到今天)沒有真正的意義。

但是自然語言的處理,是一個重要問題,也需要自動化的支援。因此人就得想辦法,讓機器能儘量理解和表示人類的語言。

假如這裡有兩句話:

I love the game.

I hate the game.

那麼我們就可以簡單粗暴地抽取出以下特徵(其實就是把所有的單詞都羅列一遍):

  • I
  • love
  • hate
  • the
  • game

對每一句話,都分別計算特徵出現個數。於是上面兩句話就轉換為以下表格:

如何用Python和機器學習訓練中文文字情感分類模型?

按照句子為單位,從左到右讀數字,第一句表示為[1, 1, 0, 1, 1],第二句就成了[1, 0, 1, 1, 1]。

這就叫向量化。

這個例子裡面,特徵的數量叫做維度。於是向量化之後的這兩句話,都有5個維度。

你一定要記住,此時機器依然不能理解兩句話的具體含義。但是它已經儘量在用一種有意義的方式來表達它們。

注意這裡我們使用的,叫做“一袋子詞”(bag of words)模型。

下面這張圖(來自 ~https://goo.gl/2jJ9Kp~ ),形象化表示出這個模型的含義。

如何用Python和機器學習訓練中文文字情感分類模型?
一袋子詞模型不考慮詞語的出現順序,也不考慮詞語和前後詞語之間的連線。每個詞都被當作一個獨立的特徵來看待。

你可能會問:“這樣不是很不精確嗎?充分考慮順序和上下文聯絡,不是更好嗎?”

沒錯,你對文字的順序、結構考慮得越周全,模型可以獲得的資訊就越多。

但是,凡事都有成本。只需要用基礎的排列組合知識,你就能計算出獨立考慮單詞,和考慮連續n個詞語(稱作 n-gram),造成的模型維度差異了。

為了簡單起見,我們們這裡還是先用一袋子詞吧。有空我再給你講講……

打住,不能再挖坑了。

中文

上一節我們們介紹的,是自然語言向量化處理的通則。

處理中文的時候,要更加麻煩一些。

因為不同於英文、法文等拉丁語系文字,中文天然沒有空格作為詞語之間的分割符號。

我們要先將中文分割成空格連線的詞語。

例如把:

“我喜歡這個遊戲”

變成:

“我 喜歡 這個 遊戲”

這樣一來,就可以仿照英文句子的向量化,來做中文的向量化了。

你可能擔心計算機處理起中文的詞語,跟處理英文詞語有所不同。

這種擔心沒必要。

因為我們們前面講過,計算機其實連英文單詞也看不懂。

在它眼裡,不論什麼自然語言的詞彙,都只是某種特定組合的字串而已。 不論處理中文還是英文,都需要處理的一種詞彙,叫做停用詞。

中文維基百科裡,是這麼定義停用詞的:

在資訊檢索中,為節省儲存空間和提高搜尋效率,在處理自然語言資料(或文字)之前或之後會自動過濾掉某些字或詞,這些字或詞即被稱為Stop Words(停用詞)。

我們們做的,不是資訊檢索,而已文字分類。

對我們們來說,你不打算拿它做特徵的單詞,就可以當作停用詞。

還是舉剛才英文的例子,下面兩句話:

I love the game.

I hate the game.

告訴我,哪些是停用詞?

直覺會告訴你,定冠詞 the 應該是。

沒錯,它是虛詞,沒有什麼特殊意義。

它在哪兒出現,都是一個意思。

一段文字裡,出現很多次定冠詞都很正常。把它和那些包含資訊更豐富的詞彙(例如love, hate)放在一起統計,就容易干擾我們把握文字的特徵。

所以,我們們把它當作停用詞,從特徵裡面剔除出去。

舉一反三,你會發現分詞後的中文語句:

“我 喜歡 這個 遊戲”

其中的“這個”應該也是停用詞吧?

答對了!

要處理停用詞,怎麼辦呢?當然你可以一個個手工來尋找,但是那顯然效率太低。

有的機構或者團隊處理過許多停用詞。他們會發現,某種語言裡,停用詞是有規律的。

他們把常見的停用詞總結出來,彙整合表格。以後只需要查表格,做處理,就可以利用先前的經驗和知識,提升效率,節約時間。

在scikit-learn中,英語停用詞是自帶的。只需要指定語言為英文,機器會幫助你自動處理它們。

但是中文……

scikit-learn開發團隊裡,大概缺少足夠多的中文使用者吧。

好訊息是,你可以使用第三方共享的停用詞表。

這種停用詞表到哪裡下載呢?

我已經幫你找到了 一個 github 專案 ,裡面包含了4種停用詞表,來自哈工大、四川大學和百度等自然語言處理方面的權威單位。

如何用Python和機器學習訓練中文文字情感分類模型?

這幾個停用詞表檔案長度不同,內容也差異很大。為了演示的方便與一致性,我們們統一先用哈工大這個停用詞表吧。

如何用Python和機器學習訓練中文文字情感分類模型?

我已經將其一併儲存到了演示目錄壓縮包中,供你下載。 # 環境 請你先到 這個網址 下載本教程配套的壓縮包。

下載後解壓,你會在生成的目錄裡面看到以下4個檔案。

如何用Python和機器學習訓練中文文字情感分類模型?

下文中,我們會把這個目錄稱為“演示目錄”。

請一定注意記好它的位置哦。

要裝Python,最簡便辦法是安裝Anaconda套裝。

請到 這個網址 下載Anaconda的最新版本。

如何用Python和機器學習訓練中文文字情感分類模型?

請選擇左側的 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 筆記本介面:

如何用Python和機器學習訓練中文文字情感分類模型?

你可以直接點選檔案列表中的demo.ipynb檔案,可以看到本教程的全部示例程式碼。

如何用Python和機器學習訓練中文文字情感分類模型?

你可以一邊看教程的講解,一邊依次執行這些程式碼。

但是,我建議的方法,是回到主介面下,新建一個新的空白 Python 3 (顯示名稱為datapy3的那個)筆記本。

如何用Python和機器學習訓練中文文字情感分類模型?

請跟著教程,一個個字元輸入相應的內容。這可以幫助你更為深刻地理解程式碼的含義,更高效地把技能內化。

如何用Python和機器學習訓練中文文字情感分類模型?

準備工作結束,下面我們開始正式輸入程式碼。

程式碼

我們讀入資料框處理工具pandas。

import pandas as pd
複製程式碼

利用pandas的csv讀取功能,把資料讀入。

注意為了與Excel和系統環境設定的相容性,該csv資料檔案採用的編碼為GB18030。這裡需要顯式指定,否則會報錯。

df = pd.read_csv('data.csv', encoding='gb18030')
複製程式碼

我們看看讀入是否正確。

df.head()
複製程式碼

前5行內容如下:

如何用Python和機器學習訓練中文文字情感分類模型?

看看資料框整體的形狀是怎麼樣的:

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()
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

從前5行看來,情感取值就是根據我們設定的規則,從評星數量轉化而來。

下面我們把特徵和標籤拆開。

X = df[['comment']]
y = df.sentiment
複製程式碼

X 是我們的全部特徵。因為我們只用文字判斷情感,所以X實際上只有1列。

X.shape
複製程式碼
(2000, 1)
複製程式碼

而y是對應的標記資料。它也是隻有1列。

y.shape
複製程式碼
(2000,)
複製程式碼

我們來看看 X 的前幾行資料。

X.head()
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

注意這裡評論資料還是原始資訊。詞語沒有進行拆分。

為了做特徵向量化,下面我們利用結巴分詞工具來拆分句子為詞語。

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和機器學習訓練中文文字情感分類模型?

單詞和標點之間都用空格分割,符合我們的要求。

下面就是機器學習的常規步驟了:我們需要把資料分成訓練集和測試集。

為什麼要拆分資料集合?

在《貸還是不貸:如何用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:]
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

這些大部分都是語氣助詞,作為停用詞去除掉,不會影響到語句的實質含義。

下面我們就要嘗試對分詞後的中文語句做向量化了。

我們讀入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()
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

我們注意到,特徵詞語五花八門,特別是很多數字都被當作特徵放在了這裡。

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()
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

可以看到,此時特徵個數從剛才的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()
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

可以看到,那些數字全都不見了。特徵數量從單一詞表法去除停用詞之後的7144個,變成了1864個。

你可能會覺得,太可惜了吧?好容易分出來的詞,就這麼扔了?

要知道,特徵多,絕不一定是好事兒。

尤其是噪聲大量混入時,會顯著影響你模型的效能。

好了,評論資料訓練集已經特徵向量化了。下面我們要利用生成的特徵矩陣來訓練模型了。

我們的分類模型,採用樸素貝葉斯(Multinomial naive bayes)。

from sklearn.naive_bayes import MultinomialNB
nb = MultinomialNB()
複製程式碼

注意我們的資料處理流程是這樣的:

  1. 特徵向量化;
  2. 樸素貝葉斯分類。

如果每次修改一個引數,或者換用測試集,我們都需要重新執行這麼多的函式,肯定是一件效率不高,且令人頭疼的事兒。而且只要一複雜,出現錯誤的機率就會增加。

幸好,Scikit-learn給我們提供了一個功能,叫做管道(pipeline),可以方便解決這個問題。

它可以幫助我們,把這些順序工作連線起來,隱藏其中的功能順序關聯,從外部一次呼叫,就能完成順序定義的全部工作。

使用很簡單,我們就把 vect 和 nb 串聯起來,叫做pipe。

from sklearn.pipeline import make_pipeline
pipe = make_pipeline(vect, nb)
複製程式碼

看看它都包含什麼步驟:

pipe.steps
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

看,我們剛才做的工作,都在管道里面了。我們可以把管道當成一個整體模型來呼叫。

下面一行語句,就可以把未經特徵向量化的訓練集內容輸入,做交叉驗證,算出模型分類準確率的均值。

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)
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

這一大串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 )應該能讓你更為清晰理解混淆矩陣的含義:

如何用Python和機器學習訓練中文文字情感分類模型?

寫到這兒,你大概能明白我們們模型的效能了。

但是總不能只把我們們訓練出的模型和無腦“笨模型”去對比吧?這也太不公平了!

下面,我們把老朋友 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]
複製程式碼

如何用Python和機器學習訓練中文文字情感分類模型?

好了,符合我們的要求。

下面我們先看模型分類準確率:

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。

小結

回顧一下,本文介紹了以下知識點:

  1. 如何用一袋子詞(bag of words)模型將自然語言語句向量化,形成特徵矩陣;
  2. 如何利用停用詞表、詞頻閾值和標記模式(token pattern)移除不想幹的偽特徵詞彙,降低模型複雜度。
  3. 如何選用合適的機器學習分類模型,對詞語特徵矩陣做出分類;
  4. 如何用管道模式,歸併和簡化機器學習步驟流程;
  5. 如何選擇合適的效能測度工具,對模型的效能進行評估和對比。

希望這些內容能夠幫助你更高效地處理中文文字情感分類工作。

討論

你之前用機器學習做過中文情感分類專案嗎?你是如何去除停用詞的?你使用的分類模型是哪個?獲得的準確率怎麼樣?歡迎留言,把你的經驗和思考分享給大家,我們一起交流討論。

喜歡請點贊。還可以微信關注和置頂我的公眾號“玉樹芝蘭”(nkwangshuyi)

如果你對資料科學感興趣,不妨閱讀我的系列教程索引貼《如何高效入門資料科學?》,裡面還有更多的有趣問題及解法。

相關文章