【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

Eastmount發表於2018-12-21

這是《Python資料探勘課程》系列文章,前面很多文章都講解了分類、聚類演算法,而這篇文章主要講解如何呼叫SnowNLP庫實現情感分析,處理的物件是豆瓣《肖申克救贖》的評論文字。文章比較基礎,希望對你有所幫助,提供些思路,也是自己教學的內容。如果文章中存在錯誤或不足之處,還請海涵。同時,推薦大家閱讀我以前的文章瞭解其他知識。

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

目錄:
一.豆瓣評論資料抓取
    1.審查網頁元素,獲取目標網站DOM樹結構
    2.Selenium抓取《肖申克救贖》評論資訊
    3.抓取前10頁評論並儲存至CSV檔案
二.情感分析預處理及詞雲顯示
三.SnowNLP情感分析
    1.SnowNLP
    2.中文分詞
    3.常見功能
    4.情感分析
四.SnowNLP情感分析例項

PSS:最近參加CSDN2018年部落格評選,希望您能投出寶貴的一票。我是59號,Eastmount,楊秀璋。投票地址:https://bss.csdn.net/m/topic/blog_star2018/index

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析
五年來寫了314篇部落格,12個專欄,是真的熱愛分享,熱愛CSDN這個平臺,也想幫助更多的人,專欄包括Python、資料探勘、網路爬蟲、影象處理、C#、Android等。現在也當了兩年老師,更是覺得有義務教好每一個學生,讓貴州學子好好寫點程式碼,學點技術,"師者,傳到授業解惑也",提前祝大家新年快樂。2019我們攜手共進,為愛而生。

前文參考:
【Python資料探勘課程】一.安裝Python及爬蟲入門介紹
【Python資料探勘課程】二.Kmeans聚類資料分析及Anaconda介紹
【Python資料探勘課程】三.Kmeans聚類程式碼實現、作業及優化
【Python資料探勘課程】四.決策樹DTC資料分析及鳶尾資料集分析
【Python資料探勘課程】五.線性迴歸知識及預測糖尿病例項
【Python資料探勘課程】六.Numpy、Pandas和Matplotlib包基礎知識
【Python資料探勘課程】七.PCA降維操作及subplot子圖繪製
【Python資料探勘課程】八.關聯規則挖掘及Apriori實現購物推薦
【Python資料探勘課程】九.迴歸模型LinearRegression簡單分析氧化物資料
【python資料探勘課程】十.Pandas、Matplotlib、PCA繪圖實用程式碼補充
【python資料探勘課程】十一.Pandas、Matplotlib結合SQL語句視覺化分析
【python資料探勘課程】十二.Pandas、Matplotlib結合SQL語句對比圖分析
【python資料探勘課程】十三.WordCloud詞雲配置過程及詞頻分析
【python資料探勘課程】十四.Scipy呼叫curve_fit實現曲線擬合
【python資料探勘課程】十五.Matplotlib呼叫imshow()函式繪製熱圖
【python資料探勘課程】十六.邏輯迴歸LogisticRegression分析鳶尾花資料
【python資料探勘課程】十七.社交網路Networkx庫分析人物關係(初識篇)
【python資料探勘課程】十八.線性迴歸及多項式迴歸分析四個案例分享
【python資料探勘課程】十九.鳶尾花資料集視覺化、線性迴歸、決策樹花樣分析
【python資料探勘課程】二十.KNN最近鄰分類演算法分析詳解及平衡秤TXT資料集讀取
【python資料探勘課程】二十一.樸素貝葉斯分類器詳解及中文文字輿情分析
【python資料探勘課程】二十二.Basemap地圖包安裝入門及基礎知識講解
【python資料探勘課程】二十三.時間序列金融資料預測及Pandas庫詳解
【python資料探勘課程】二十四.KMeans文字聚類分析互動百科語料
【python資料探勘課程】二十五.Matplotlib繪製帶主題及聚類類標的散點圖


一.豆瓣評論資料抓取

本文首先需要抓取豆瓣《肖申克救贖》電影的評論資訊,採用Selenium爬蟲實現。這裡不再詳細講解爬蟲的知識,僅簡單介紹。

1.審查網頁元素,獲取目標網站DOM樹結構
目標網址為:https://movie.douban.com/subject/1292052/comments?start=0&limit=0&sort=new_score&status=P

如下圖所示:

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

接著通過瀏覽器定位節點找到需要抓取內容的位置。

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

每一個評論都位於 < div class=“comment-item” > 中,定位內容包括:
(1) 使用者名稱及其超連結定位class為“avatar”節點下的超連結;
(2) 評論人數位於span標籤class為“comment-vote”中的第一個span;
(3) 使用者評分位於span標籤class為“comment-info”中第二個span;
(4) 短評論位於span標籤class為“short”。

<div class="comment-item" data-cid="477351">
        <div class="avatar">
            <a title="犀牛" href="https://www.douban.com/people/whiterhinoceros/">
                ...
            </a>
        </div>
    <div class="comment">
            <span class="comment-vote">
                <span class="votes">10667</span>
                ...
            </span>
            <span class="comment-info">
                    ...
                    <span class="allstar50 rating" title="力薦"></span>
                <span class="comment-time " title="2005-10-28 00:28:07">
                    2005-10-28
                </span>
            </span>
        </h3>
        <p class="">
            
                <span class="short">當年的奧斯卡頒獎禮上...</span>
        </p>
    </div>
</div>

2.Selenium抓取《肖申克救贖》評論資訊
Python程式碼如下所示,抓取了第一頁的評論資訊,這段程式碼重點是Selenium的定位方法,而下一部分程式碼重點是將前10頁評論抓取並儲存至CSV檔案中。

# coding=utf-8  
from selenium import webdriver  
from selenium.webdriver.common.keys import Keys  
import selenium.webdriver.support.ui as ui  
from selenium.webdriver.common.action_chains import ActionChains  
import time      
import re      
import os
import csv

#開啟Firefox瀏覽器
driver = webdriver.Firefox()
i = 0
while i<1:
    num = i*20
    url = "https://movie.douban.com/subject/1292052/comments?start=" + str(num) +"&limit=20&sort=new_score&status=P"
    print url
    driver.get(url)
    #使用者姓名 超連結
    elem1 = driver.find_elements_by_xpath("//div[@class='avatar']/a")
    for n in elem1:
        print n.get_attribute("title"), 
        print n.get_attribute("href")
        
    #使用者評分
    elem2 = driver.find_elements_by_xpath("//span[@class='comment-info']/span[2]")
    for n in elem2:
        print n.get_attribute("class"), 
        print n.get_attribute("title")

    #有用數
    elem3 = driver.find_elements_by_xpath("//span[@class='comment-vote']/span[1]")
    for n in elem3:
        print n.text
        
    #日期
    elem4 = driver.find_elements_by_xpath("//span[@class='comment-time ']")
    for n in elem4:
        print n.text

    #評論
    elem5 = driver.find_elements_by_xpath("//span[@class='short']")
    for n in elem5:
        print n.text
        
    i = i + 1

輸出結果如下所示:

>>> 
犀牛 https://www.douban.com/people/whiterhinoceros/
kingfish https://www.douban.com/people/kingfish/
Eve|Classified https://www.douban.com/people/eve42/
...

allstar50 rating 力薦
allstar40 rating 推薦
allstar30 rating 還行
...

10667
19919
4842
...

2005-10-28
2006-03-22
2008-05-09
...

當年的奧斯卡頒獎禮上,被如日中天的《阿甘正傳》...
不需要女主角的好電影
有種鳥是關不住的.
...
>>>

3.抓取前10頁評論並儲存至CSV檔案
完整程式碼如下所示:

# coding=utf-8  
from selenium import webdriver  
from selenium.webdriver.common.keys import Keys  
import selenium.webdriver.support.ui as ui  
from selenium.webdriver.common.action_chains import ActionChains  
import time      
import re      
import os
import csv
import codecs

#寫入檔案
c = open("test-douban.csv", "wb")  #寫檔案
c.write(codecs.BOM_UTF8)          #防止亂碼
writer = csv.writer(c)                     #寫入物件
writer.writerow(['序號','使用者名稱','連結','評分','評分標題','有用數','日期','評論'])

#開啟Firefox瀏覽器 設定等待載入時間 訪問URL  
driver = webdriver.Firefox()
i = 0
while i<1:
    num = i*20
    url = "https://movie.douban.com/subject/1292052/comments?start=" + str(num) +"&limit=20&sort=new_score&status=P"
    print url
    driver.get(url)
    #使用者姓名 超連結
    elem1 = driver.find_elements_by_xpath("//div[@class='avatar']/a")     
    #使用者評分
    elem2 = driver.find_elements_by_xpath("//span[@class='comment-info']/span[2]")
    #有用數
    elem3 = driver.find_elements_by_xpath("//span[@class='comment-vote']/span[1]")
    #日期
    elem4 = driver.find_elements_by_xpath("//span[@class='comment-time ']")
    #評論
    elem5 = driver.find_elements_by_xpath("//span[@class='short']")

    #迴圈寫入20行評價
    tlist = []
    k = 0
    while k<20:
        #序號
        num = i*20+k+1
        print num
        #使用者姓名
        name = elem1[k].get_attribute("title").encode('utf-8')
        print name
        #超連結
        href = elem1[k].get_attribute("href").encode('utf-8')
        print href
        #使用者評分及內容
        score = elem2[k].get_attribute("class").encode('utf-8')
        print score
        content = elem2[k].get_attribute("title").encode('utf-8')
        print content
        #有用數
        useful = elem3[k].text.encode('utf-8')
        print useful
        #日期
        date = elem4[k].text.encode('utf-8')
        #評論
        shortcon = elem5[k].text.encode('utf-8')
        print shortcon

        #寫入檔案
        templist = []
        templist.append(num)
        templist.append(name)
        templist.append(href)
        templist.append(score)
        templist.append(content)
        templist.append(useful)
        templist.append(date)
        templist.append(shortcon)
        writer.writerow(templist)
        
        k = k + 1
            
    i = i + 1

c.close()

執行結果如下圖所示:

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析
【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

二.情感分析預處理及詞雲顯示

情感分析的基本流程如下圖所示,通常包括:
1.自定義爬蟲抓取文字資訊;
2.使用Jieba工具進行中文分詞、詞性標註;
3.定義情感詞典提取每行文字的情感詞;
4.通過情感詞構建情感矩陣,並計算情感分數;
5.結果評估,包括將情感分數置於0.5到-0.5之間,並視覺化顯示。

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

本文將抓取的200條《肖申克救贖》評論資訊複製至TXT檔案中 ,每一行為一條評論,再對其進行中文分詞處理。注意,這裡僅僅獲取序號1-200的情感分數,而其他情感分析可以進行時間對比、主題對比等,這裡作者也爬取了完整資訊,而不僅僅是評論,就為了方便讀者實驗。其方法和此篇文章類似,希望讀者學會舉一反三。

data.txt

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

下面這段程式碼主要講解Python呼叫Jieba工具進行分詞,然後通過WordCloud庫實現詞雲顯示,關鍵詞出現越多顯示越大,比如“希望”、“自由”、“電影”等。

# -*- coding: utf-8 -*-
import jieba
import sys
import matplotlib.pyplot as plt
from wordcloud import WordCloud
 
#開啟本體TXT檔案
text = open('data.txt').read()
print type(text)
 
#結巴分詞 cut_all=True 設定為精準模式 
wordlist = jieba.cut(text, cut_all = False)
 
#使用空格連線 進行中文分詞
wl_space_split = " ".join(wordlist)
print wl_space_split
 
#對分詞後的文字生成詞雲
my_wordcloud = WordCloud().generate(wl_space_split)
 
#顯示詞雲圖
plt.imshow(my_wordcloud)
#是否顯示x軸、y軸下標
plt.axis("off")
plt.show()
【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

分詞過程如下圖所示,通過空格連線。

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

三.SnowNLP情感分析

1.SnowNLP
SnowNLP是一個常用的Python文字分析庫,是受到TextBlob啟發而發明的。由於當前自然語言處理庫基本都是針對英文的,而中文沒有空格分割特徵詞,Python做中文文字挖掘較難,後續開發了一些針對中文處理的庫,例如SnowNLP、Jieba、BosonNLP等。注意SnowNLP處理的是unicode編碼,所以使用時請自行decode成unicode。

Snownlp主要功能包括:

  • 中文分詞(演算法是Character-Based Generative Model)
  • 詞性標註(原理是TnT、3-gram 隱馬)
  • 情感分析
  • 文字分類(原理是樸素貝葉斯)
  • 轉換拼音、繁體轉簡體
  • 提取文字關鍵詞(原理是TextRank)
  • 提取摘要(原理是TextRank)、分割句子
  • 文字相似(原理是BM25)

推薦官網給大家學習。
安裝和其他庫一樣,使用pip安裝即可。

pip install snownlp

2.中文分詞
下面是最簡單的例項,使用SnowNLP進行中文分詞,同時比較了SnowNLP和Jieba庫的分詞效果。

# -*- coding: utf-8 -*-
from snownlp import SnowNLP
s1 = SnowNLP(u"這本書質量真不太好!")
print("SnowNLP:")
print(" ".join(s1.words))

import jieba
s2 = jieba.cut(u"這本書質量真不太好!", cut_all=False)
print("jieba:")
print(" ".join(s2))

輸出結果如下所示:

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

總體感覺是SnowNLP分詞速度比較慢,準確度較低,比如“不太好”這個片語,但也不影響我們後續的情感分析。

3.常見功能
程式碼如下:

# -*- coding: utf-8 -*-
from snownlp import SnowNLP
s = SnowNLP(u"這本書質量真不太好!")

print(u"\n中文分詞:")
print( " ".join(s.words))

print(u"\n詞性標註:")
print(s.tags)
for k in s.tags:
    print(k)

print(u"\n情感分數:")
print(s.sentiments)

print(u"\n轉換拼音:")
print(s.pinyin)

print(u"\n輸出前4個關鍵詞:")
print(s.keywords(4))
for k in s.keywords(4):
    print(k)

print(u"\n輸出關鍵句子:")
print(s.summary(1))
for k in s.summary(1):
    print(k)

print(u"\n輸出tf和idf:")
print(s.tf)
print(s.idf)

n = SnowNLP(u'「繁體字」「繁體中文」的叫法在臺灣亦很常見。')
print(u"\n繁簡體轉換:")
print(n.han)

s.words 輸出分詞後的結果,詞性標註主要通過 s.tags,s.sentiments 計算情感分數,s.pinyin 轉換為拼音,s.keywords(4) 提取4個關鍵詞,s.summary(1) 輸出一個關鍵句子,s.tf 計算TF值(頻率),s.idf 計算IDF值(倒文件)。

輸出結果如下所示:

>>> 

中文分詞:
這 本書 質量 真 不 太 好 !

詞性標註:
[(u'\u8fd9', u'r'), (u'\u672c\u4e66', u'r'), (u'\u8d28\u91cf', u'n'), 
(u'\u771f', u'd'), (u'\u4e0d', u'd'), (u'\u592a', u'd'), 
(u'\u597d', u'a'), (u'\uff01', u'w')]
(u'\u8fd9', u'r')
(u'\u672c\u4e66', u'r')
(u'\u8d28\u91cf', u'n')
(u'\u771f', u'd')
(u'\u4e0d', u'd')
(u'\u592a', u'd')
(u'\u597d', u'a')
(u'\uff01', u'w')

情感分數:
0.420002029202

轉換拼音:
[u'zhe', u'ben', u'shu', u'zhi', u'liang', u'zhen', u'bu', u'tai', u'hao', u'\uff01']

輸出前4個關鍵詞:
[u'\u592a', u'\u4e0d', u'\u8d28\u91cf', u'\u771f']
太
不
質量
真

輸出關鍵句子:
[u'\u8fd9\u672c\u4e66\u8d28\u91cf\u771f\u4e0d\u592a\u597d']
這本書質量真不太好

輸出tf和idf:
[{u'\u8fd9': 1}, {u'\u672c': 1}, {u'\u4e66': 1}, 
{u'\u8d28': 1}, {u'\u91cf': 1}, {u'\u771f': 1}, 
{u'\u4e0d': 1}, {u'\u592a': 1}, {u'\u597d': 1}, {u'\uff01': 1}]
{u'\uff01': 1.845826690498331, u'\u4e66': 1.845826690498331, u'\u8d28': 1.845826690498331, 
u'\u592a': 1.845826690498331, u'\u4e0d': 1.845826690498331, u'\u672c': 1.845826690498331, 
u'\u91cf': 1.845826690498331, u'\u8fd9': 1.845826690498331, u'\u597d': 1.845826690498331, u'\u771f': 1.845826690498331}

繁簡體轉換:
「繁體字」「繁體中文」的叫法在臺灣亦很常見。
>>> 

同樣可以進行文字相似度計算,程式碼參考下圖所示:

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

4.情感分析
SnowNLP情感分析也是基於情感詞典實現的,其簡單的將文字分為兩類,積極和消極,返回值為情緒的概率,越接近1為積極,接近0為消極。其原理參考zhiyong_will大神和鄧旭東老師的文章,也強烈推薦大家學習。地址:
情感分析——深入snownlp原理和實踐
自然語言處理庫之snowNLP

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

下面簡單給出一個情感分析的例子:

# -*- coding: utf-8 -*-
from snownlp import SnowNLP
s1 = SnowNLP(u"我今天很開心")
print(u"s1情感分數:")
print(s1.sentiments)

s2 = SnowNLP(u"我今天很沮喪")
print(u"s2情感分數:")
print(s2.sentiments)

s3 = SnowNLP(u"大傻瓜,你脾氣真差,動不動就打人")
print(u"s3情感分數:")
print(s3.sentiments)

輸出結果如下所示,當負面情感特徵詞越多,比如“傻瓜”、“差”、“打人”等,分數就會很低,同樣當正免情感詞多分數就高。

s1情感分數:
0.84204018979
s2情感分數:
0.648537121839
s3情感分數:
0.0533215596706

而在真實專案中,通常需要根據實際的資料重新訓練情感分析的模型,匯入正面樣本和負面樣本,再訓練新模型。
sentiment.train(’./neg.txt’, ‘./pos.txt’)
sentiment.save(‘sentiment.marshal’)


四.SnowNLP情感分析例項

下面的程式碼就是對爬取的豆瓣電影《肖申克的救贖》評論進行情感分析。
1.情感各分數段出現頻率
首先統計各情感分數段出現的評率並繪製對應的柱狀圖,程式碼如下:

# -*- coding: utf-8 -*-
from snownlp import SnowNLP
import codecs
import os

source = open("data.txt","r")
line = source.readlines()
sentimentslist = []
for i in line:
    s = SnowNLP(i.decode("utf-8"))
    print(s.sentiments)
    sentimentslist.append(s.sentiments)

import matplotlib.pyplot as plt
import numpy as np
plt.hist(sentimentslist, bins = np.arange(0, 1, 0.01), facecolor = 'g')
plt.xlabel('Sentiments Probability')
plt.ylabel('Quantity')
plt.title('Analysis of Sentiments')
plt.show()

輸出結果如下圖所示:

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

對應的分數如下:

>>>
1.0
0.945862922561
1.0
0.979234476526
0.750839957904
0.491062087241
0.936143577844
0.641496807331
...

2.情感波動分析
接下來分析200條評論,每條評論的波動情況,程式碼如下所示:

# -*- coding: utf-8 -*-
from snownlp import SnowNLP
import codecs
import os

source = open("data.txt","r")
line = source.readlines()
sentimentslist = []
for i in line:
    s = SnowNLP(i.decode("utf-8"))
    print(s.sentiments)
    sentimentslist.append(s.sentiments)

import matplotlib.pyplot as plt
import numpy as np
plt.plot(np.arange(0, 200, 1), sentimentslist, 'k-')
plt.xlabel('Number')
plt.ylabel('Sentiment')
plt.title('Analysis of Sentiments')
plt.show()

輸出結果如下所示,呈現一條曲線,因為抓取的評論基本都是好評,所以分數基本接近於1.0,而真實分析過程中存在好評、中評和差評,曲線更加規律。

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

同時,在做情感分析的時候,我看到很多論文都是將情感區間從[0, 1.0]轉換為[-0.5, 0.5],這樣的曲線更加好看,位於0以上的是積極評論,反之消極評論。修改程式碼如下:

# -*- coding: utf-8 -*-
from snownlp import SnowNLP
import codecs
import os

#獲取情感分數
source = open("data.txt","r")
line = source.readlines()
sentimentslist = []
for i in line:
    s = SnowNLP(i.decode("utf-8"))
    print(s.sentiments)
    sentimentslist.append(s.sentiments)

#區間轉換為[-0.5, 0.5]
result = []
i = 0
while i<len(sentimentslist):
    result.append(sentimentslist[i]-0.5)
    i = i + 1

#視覺化畫圖
import matplotlib.pyplot as plt
import numpy as np
plt.plot(np.arange(0, 200, 1), result, 'k-')
plt.xlabel('Number')
plt.ylabel('Sentiment')
plt.title('Analysis of Sentiments')
plt.show()

繪製圖形如下所示:

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

3.建議
這裡簡單補充五個建議,具體如下:
(1)情感分析通常需要和評論時間結合起來,並進行輿情預測等,建議讀者嘗試將時間結合。比如王樹義老師的文章《基於情感分類的競爭企業新聞文字主題挖掘》。

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

(2)情感分析也是可以進行評價的,我們前面抓取的分為5星評分,假設0-0.2位一星,0.2-0.4位二星,0.4-0.6為三星,0.6-0.8為四星,0.8-1.0為五星,這樣我們可以計算它的準確率,召回率,F值,從而評論我的演算法好壞。

(3)作者還有很多情感分析結合冪率分佈的知識,因為需要寫文章,這裡暫時不進行分享,但是這篇基礎文章對初學者仍然有一定的幫助。

(4)BosonNLP也是一個比較不錯的情感分析包,建議感興趣的讀者學習,它提供了相關的詞典,如下:https://bosonnlp.com/dev/resource。

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

(5)讀者如果不太擅長寫程式碼,可以嘗試使用情感分析系統。http://ictclas.nlpir.org/nlpir/
比如分析評論:
當年的奧斯卡頒獎禮上,被如日中天的《阿甘正傳》掩蓋了它的光彩,而隨著時間的推移,這部電影在越來越多的人們心中的地位已超越了《阿甘》。每當現實令我疲憊得產生無力感,翻出這張碟,就重獲力量。毫無疑問,本片位列男人必看的電影前三名!回顧那一段經典臺詞:“有的人的羽翼是如此光輝,即使世界上最黑暗的牢獄,也無法長久地將他圍困!”

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析 【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析 【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

基礎性文章,希望對大家有所幫助,不喜勿噴,2018年馬上結束,祝大家新年快樂,學到更多知識,認識這個大千世界。也推薦下我的年終總結文章。
2018年總結:向死而生,為愛而活——憶程式設計青椒的戎馬歲月

【python資料探勘課程】二十六.基於SnowNLP的豆瓣評論情感分析

(By:Eastmount 2018-12-21 中午12點 http://blog.csdn.net/eastmount/ )


相關文章