用機器學習做中文情感分類

文本情感分析

文本情感分析(也稱為意見挖掘)是指用自然語言處理藏畅、文本挖掘以及計算機語言學等方法來識別和提取原素材中的主觀信息。

通常來說功咒,情感分析的目的是為了找出說話者/作者在某些話題上或者針對一個文本兩極的觀點的態(tài)度愉阎。這個態(tài)度或許是他或她的個人判斷或是評估,也許是他當時的情感狀態(tài)(就是說力奋,作者在做出這個言論時的情緒狀態(tài))榜旦,或是作者有意向的情感交流(就是作者想要讀者所體驗的情緒)。

書籍評論數(shù)據(jù)

我們將使用從豆瓣網(wǎng)收集的《解憂雜貨店》書籍相關(guān)評論數(shù)據(jù)景殷,書籍整體評分在8.5分溅呢,大多數(shù)都是4星或者5星。選取該書籍的原因主要在于收集足夠的樣本進行建模猿挚,考慮該書籍是東野圭吾的熱門小說咐旧,主頁顯示接近40w的評價,短評約13w亭饵,初略估計每個星類別都有幾千的評論休偶。當然這本書的內(nèi)容也是挺不錯的,有興趣的讀者可以去看看哦辜羊。踏兜。

收集的數(shù)據(jù)包含文本評論和對應的星級評分,文本評論用來做情感分類的輸入數(shù)據(jù)八秃,豆瓣評分用來表示該評論是“正面”還是“負面”碱妆。豆瓣的評分包含1~5星的打分,為了簡化建模過程昔驱,我們將評論打分處理成二分類疹尾,評分1分和2分的評論標記為“負面”,評分4分和5分的評論標記為“正面”骤肛,3分歸類為中性評論纳本,所以不包含在數(shù)據(jù)集中。這里就不討論3分不包含數(shù)據(jù)集中的處理方式腋颠,有興趣的讀者可以看看3分的相關(guān)評論繁成。

加載數(shù)據(jù)集

使用Pandas可以很方便的讀取評論數(shù)據(jù),我們用Jupyter notebook來執(zhí)行代碼淑玫,方便我們查看數(shù)據(jù)情況巾腕。加載數(shù)據(jù)集后查看前五條數(shù)據(jù),對于中文文本有時候會出現(xiàn)編碼問題絮蒿,確認目前數(shù)據(jù)沒有發(fā)生該問題尊搬。

import pandas as pd

# 讀取評論數(shù)據(jù)集
df = pd.read_excel('data/comment.xlsx')

df.head()
評論數(shù)據(jù)

數(shù)據(jù)探索

接下來我們查看整個數(shù)據(jù)集的記錄數(shù)以及每個評分的記錄數(shù)⊥晾裕總共有4352條評論佛寿,其中一半為1分或2分,一半為4分或5分狗准。原始數(shù)據(jù)中絕大部分評論數(shù)據(jù)的評分都是4分或5分,為了防止訓練模型的時候因數(shù)據(jù)集分類數(shù)量差異導致模型“記憶”更多的“正面”評論腔长,經(jīng)過處理使得目前使用的數(shù)據(jù)集二分類各占一半。

## 查看數(shù)據(jù)形狀
print(df.shape)

# 查看分數(shù)分布
print(df['rating'].value_counts())

(4352, 2)

2 1735
5 1250
4 926
1 441

最后捞附,檢查數(shù)據(jù)集有無缺失值,遍歷后所有列均沒有缺失值鸟召。

# 查看有無空值
for col in df.columns:
    print(col, ':', len(df[df[col].isnull()]))

id : 0
comment : 0
rating : 0

數(shù)據(jù)預處理

由于這是一個二分類問題,我們需要將評分轉(zhuǎn)化為只含兩種標簽的數(shù)據(jù)欧募。rating列大于3的標記為1,其余標記為0仆抵,并指定新的label列跟继。

df['label'] = df['rating'].map(lambda x: 1 if x > 3 else 0)

中文分詞

用于機器學習文本最簡單且最常用的方法是使用詞袋(bag-of-words)表示种冬。為了表示詞袋需要將評論分成一個個單詞,并計算每個單詞在評論中出現(xiàn)的頻次舔糖。這種表示方法有個缺點娱两,即舍棄了文本中的大部分結(jié)構(gòu),段落金吗、句子十兢、格式。英文每個單詞都用空格隔開比較好處理摇庙,對于中文句子我們需要使用分詞庫將句子分割成單詞旱物,不同分詞庫具體案例可以看我之前寫過的文章《Python中文分詞及詞頻統(tǒng)計》。

這里我們使用jieba分詞庫進行快速分詞卫袒,由于可能有全數(shù)字的文本評論會導致文本分詞報錯宵呛,這里先進行類型轉(zhuǎn)換。

import jieba

# jieba分詞
df['comment'] = df['comment'].map(str)
df['cuted'] = df['comment'].map(lambda x: ' '.join(jieba.cut(x)))

訓練集和測試集

為了驗證數(shù)據(jù)準確率玛臂,對于文本數(shù)據(jù)同樣需要進行劃分數(shù)據(jù)集烤蜕。大寫X表示輸入,小寫y表示輸出迹冤。sklearn機器學習庫的train_test_split可以很方便進行劃分數(shù)據(jù)集讽营,默認25%做為測試集,random_state指定隨機種子保證每次劃分的結(jié)果是一致的泡徙。

# 輸入和輸出
X = df['cuted']
y = df['label']
from sklearn.model_selection import train_test_split

# 劃分訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# 查看訓練集
X_train.shape

CountVectorizer類可以實現(xiàn)文本的詞袋表示橱鹏,實例化對象后進行擬合,vocabulary_屬性可以看到詞表堪藐,每個單詞對應的索引莉兰,不是頻次。從打印的信息可以看到我們總共有7349個單詞礁竞。

from sklearn.feature_extraction.text import CountVectorizer

# 變換器
vect = CountVectorizer()

vect.fit(X_train)

# 詞表數(shù)量
print(len(vect.vocabulary_))
# 打印詞表
print(vect.vocabulary_)
詞表

我們可以調(diào)用transform方法來創(chuàng)建詞袋的稀疏矩陣糖荒,矩陣中每個特征對應詞表中的單詞,如果沒有這個單詞會用0進行填充模捂。

words_matrix = pd.DataFrame(vect.transform(X).toarray(),
                            columns=vect.get_feature_names())

words_matrix.head()
詞矩陣

構(gòu)建模型

在提取特征后捶朵,我們通過構(gòu)建LogisticRegression邏輯回歸分類器來擬合訓練集數(shù)據(jù),并使用交叉驗證對LogisticRegression進行評估模型的性能狂男。我們的得到的交叉驗證分數(shù)是81.9%,這對于二分類模型來說還是比較合理的岖食。通常在這種多維特征的數(shù)據(jù)進行擬合分類邏輯回歸都有不錯的效果泡垃。

iimport numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score

# 交叉驗證評估模型
scores = cross_val_score(LogisticRegression(),
                         vect.transform(X_train), y_train, cv=5)
print('平均交叉驗證準確率:{:.3f}'.format(np.mean(scores)))

平均交叉驗證準確率: 0.819

去除停用詞

回過頭看我們會發(fā)現(xiàn)單詞特征中包含很多數(shù)字及其他如“的”、“哦”等單詞唾琼,這些單詞在大多數(shù)情況下對于我們目前的案例沒有提供有效的信息量澎剥,所以需要從原來的詞袋中刪除掉以提高模型的性能哑姚,對于這些特定詞我們稱之為停用詞。這里使用哈工大的停用詞表倡蝙,創(chuàng)建函數(shù)讀取詞表并刪除換行符寺鸥,輸出停用詞列表品山。

def stopwords_list():
    with open('哈工大停用詞表.txt') as f:
        lines = f.readlines()
        result = [i.strip('\n') for i in lines]
    return result

stopwords = stopwords_list()

重新構(gòu)建單詞矩陣肘交,max_df參數(shù)表示舍棄最頻繁的單詞,min_df參數(shù)表示每個詞必須要在3個評論中出現(xiàn)凉驻,stop_words參數(shù)對于中文需要指定停用詞列表,最后使用正則表達式去掉所有數(shù)字间狂,處理完后可以看到單詞由7349個減少到1931個。

vect = CountVectorizer(max_df=0.8, min_df=3, stop_words=stopwords,
                       token_pattern=u'(?u)\\b[^\\d\\W]\\w+\\b')

vect.fit(X_train)

words_matrix = pd.DataFrame(vect.transform(X_train).toarray(),
                            columns=vect.get_feature_names())

再次評估新的詞袋模型蛛淋,似乎準確率上沒有提升褐荷,這是對于幾千樣本的數(shù)據(jù)叛甫。在幾萬樣本的情況下,通常單詞特征會有幾萬個萌腿,這個時候采用去除停用詞是可以明顯降低數(shù)據(jù)中的噪聲抖苦,提高模型的準確率。不過這里不要擔心我們繼續(xù)優(yōu)化贮庞。

# 訓練模型
lr.fit(vect.transform(X_train), y_train)

print('測試集準確率:{:.3f}'.format(lr.score(vect.transform(X_test), y_test)))

測試集準確率:0.812

用tf-idf縮放數(shù)據(jù)

tf-idf 是一種用于資訊檢索與文本挖掘的常用加權(quán)技術(shù)窗慎。tf-idf 是一種統(tǒng)計方法遮斥,用以評估一字詞對于一個文件集或一個語料庫中的其中一份文件的重要程度扇丛。字詞的重要性隨著它在文件中出現(xiàn)的次數(shù)成正比增加晕拆,但同時會隨著它在語料庫中出現(xiàn)的頻率成反比下降。tf-idf 加權(quán)的各種形式常被搜索引擎應用吝镣,作為文件與用戶查詢之間相關(guān)程度的度量或評級末贾。除了 tf-idf 以外整吆,互聯(lián)網(wǎng)上的搜尋引擎還會使用基于連結(jié)分析的評級方法,以確定文件在搜尋結(jié)果中出現(xiàn)的順序拴测。

scikit-learn 在兩個類中實現(xiàn)了 tf-idf 方法:TfidfTransformerTfidfVectorizer集索, 前者接受 CountVectorizer 生成的稀疏矩陣并將其變換务荆, 后者接受文本 數(shù)據(jù)并完成詞袋特征提取與 tf-idf 變換。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import make_pipeline

pipe = make_pipeline(TfidfVectorizer(min_df=3), LogisticRegression())
pipe.fit(X_train, y_train)
scores = cross_val_score(pipe, X_train, y_train, cv=5)
print('平均交叉驗證準確率:{:.3f}'.format(np.mean(scores)))

平均交叉驗證準確率:0.828

我們可以看到使用 tf-idf 代替僅統(tǒng)計詞數(shù)對性能有所提高娱据。我們還可以查看 tf-idf 找到的最重要的單詞中剩。tf-idf較低的詞要么在評論中經(jīng)常出現(xiàn)咽安,要么就是很少出現(xiàn)蓬推,tf-idf較大的詞往往在評論中經(jīng)常出現(xiàn)澡腾。

vectorizer = pipe.named_steps['tfidfvectorizer']
# 找到每個特征中最大值
max_value = vectorizer.transform(X_train).max(axis=0).toarray().ravel()
sorted_by_tfidf = max_value.argsort()
# 獲取特征名稱
feature_names = np.array(vectorizer.get_feature_names())

print("tfidf較低的特征:\n{}".format(feature_names[sorted_by_tfidf[:20]]))
print()
print("tfidf較高的特征:\n{}".format( feature_names[sorted_by_tfidf[-20:]]))

評估模型

最后我們在使用測試集驗證模型的準確率毅糟,可以看到模型最終在測試集上有81.4%的準確率澜公,前面做的交叉驗證僅僅只是在訓練集上坟乾。另外,模型混淆矩陣上看到模型在負類上的準確率為448 / (448 + 99) = 0.81.9明吩,正類上的準確率為438 / (438 + 103) = 0.81印荔。

from sklearn import metrics

# 預測值
y_pred = pipe.predict(X_test)

print('測試集準確率:{:.3f}'.format(metrics.accuracy_score(y_test, y_pred)))
print('測試集準確率:{:.3f}'.format(pipe.score(X_test, y_test)))

metrics.confusion_matrix(y_test, y_pred)

測試集準確率:0.814
測試集準確率:0.814

array([[448, 103], [ 99, 438]])

混淆矩陣

豆瓣評分的思考

前段時間“流浪地球”電影刷分的事件鬧得沸沸揚揚仍律,那些高分改評論的內(nèi)容實際上可以使用機器學習進行修正水泉,即如果發(fā)現(xiàn)評論內(nèi)容判定為正面情感,而評分給出1分或2分則表示該評論與評分很可能不相符躯概,針對這種數(shù)據(jù)可以對該評論的星級評分進行降權(quán)娶靡,權(quán)重可以根據(jù)評分的人數(shù)進行調(diào)整看锉。當然使用簡單的機器學習系統(tǒng)還是要依靠大量的樣本數(shù)據(jù)、合理的模型以及合理的參數(shù)呻此,80%的準確率相當于有可能20%的誤判焚鲜。當然我們還有其他技巧可以再次提高我們模型的準確率放前,例如使用預訓練好的詞嵌入向量和使用更加高級的深度學習模型,期待我們的再次相會吧~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末葱她,一起剝皮案震驚了整個濱河市吨些,隨后出現(xiàn)的幾起案子豪墅,更是在濱河造成了極大的恐慌辆脸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異倘是,居然都是意外死亡,警方通過查閱死者的電腦和手機叨粘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門升敲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人驴党,你說我怎么就攤上這事港庄。” “怎么了渤涌?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵实蓬,是天一觀的道長瞳秽。 經(jīng)常有香客問我率翅,道長袖迎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮归形,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暇榴。我一直安慰自己蔼紧,他們只是感情好,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布彬犯。 她就那樣靜靜地躺著,像睡著了一般湖蜕。 火紅的嫁衣襯著肌膚如雪重荠。 梳的紋絲不亂的頭發(fā)上虚茶,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音婆殿,去河邊找鬼婆芦。 笑死喂饥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的或粮。 我是一名探鬼主播捞高,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼氢哮,長吁一口氣:“原來是場噩夢啊……” “哼型檀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起胀溺,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤碍讯,失蹤者是張志新(化名)和其女友劉穎扯躺,沒想到半個月后蝎困,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體禾乘,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡始藕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年伍派,在試婚紗的時候發(fā)現(xiàn)自己被綠了剩胁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡晾腔,死狀恐怖灼擂,靈堂內(nèi)的尸體忽然破棺而出觉至,到底是詐尸還是另有隱情,我是刑警寧澤领斥,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布沃暗,位于F島的核電站孽锥,受9級特大地震影響细层,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盛撑,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一抵卫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧介粘,春花似錦、人聲如沸雅采。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铐望。三九已至,卻和暖如春督弓,著一層夾襖步出監(jiān)牢的瞬間乒验,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鳄厌,地道東北人了嚎。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓歪泳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敌卓。 傳聞我的和親對象是個殘疾皇子伶氢,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 看專業(yè)深奧一點的書惧蛹,總是昏昏欲睡扇救,三心二意香嗓,喝喝水靠娱,吃吃西瓜沧烈,最后在感嘆一天的時間怎么這么快就過了锌雀,今天看了一些專...
    堤娜閱讀 354評論 2 2
  • 今天收拾家太累腋逆,腳疼侈贷,實在沒有力氣再寫一個月總結(jié)了,聊聊幾筆帶過吧俏蛮。 感謝這個寫手圈一個月的打卡簽到撑蚌,學會每天寫字...
    云隱霧輕閱讀 185評論 0 0
  • 作家就是寫文章的人。作家又分詩人搏屑、散文家争涌、小說家、評論家……等等辣恋。 在文字領(lǐng)域第煮,作家?guī)缀鯖]有全才。我個人所見抑党,作家...
    宗林的李閱讀 791評論 3 4
  • 早上出門從電梯走出來,感覺有些陰冷撵摆。 中午太陽又出來了底靠,這也算是冬日的暖陽了。 周六剛好是一周年紀念日特铝,時間總是眨...
    王小小二兒閱讀 448評論 0 0
  • 想必各位讀者都遇到過這樣的情況: 畢業(yè)或者辭職后砍的,肯定要找一份新的工作廓鞠,于是我們開始投簡歷滋早,然后去面試。 面試是一...
    番茄知識閱讀 526評論 0 0