1. 程式人生 > >基於情感詞典的python情感分析

基於情感詞典的python情感分析

近期老師給我們安排了一個大作業,要求根據情感詞典對微博語料進行情感分析。於是在網上狂找資料,看相關書籍,終於搞出了這個任務。現在做做筆記,總結一下本次的任務,同時也給遇到有同樣需求的人,提供一點幫助。

1、情感分析含義

情感分析指的是對新聞報道、商品評論、電影影評等文字資訊進行觀點提取、主題分析、情感挖掘。情感分析常用於對某一篇新聞報道積極消極分析、淘寶商品評論情感打分、股評情感分析、電影評論情感挖掘。情感分析的內容包括:情感的持有者分析、態度持有者分析、態度型別分析(一系列型別如喜歡(like),討厭(hate),珍視(value),渴望(desire)等;或著簡單的加權極性如積極(positive),消極(negative)和中性(neutral)並可用具體的權重修飾)、態度的範圍分析(包含每句話,某一段、或者全文)。因此,情感分析的目的可以分為:初級

:文章的整體感情是積極/消極的;進階:對文章的態度從1-5打分;高階:檢測態度的目標,持有者和型別。

總的來說,情感分析就是對文字資訊進行情感傾向挖掘。

2、情感挖掘方法

情感挖掘目前主要使用的方法是使用情感詞典,對文字進行情感詞匹配,彙總情感詞進行評分,最後得到文字的情感傾向。本次我主要使用了兩種方法進行情感分析。第一種:基於BosonNLP情感詞典。該情感詞典是由波森自然語言處理公司推出的一款已經做好標註的情感詞典。詞典中對每個情感詞進行情感值評分,bosanNLP情感詞典如下圖所示:

 

第二種,採用的是知網推出的情感詞典,以及極性表進行情感分析。知網提供的情感詞典共用12個檔案,分為英文和中文。其中中文情感詞典包括:評價、情感、主張、程度(正面、負面)的情感文字。本文將評價和情感詞整合作為情感詞典使用,程度詞表中含有的程度詞,按照等級區分,分為:most(最高)-very(很、非常)-more(更多、更)-ish(稍、一點點)-insufficiently(欠、不)-over(過多、多分、多)六個情感程度詞典。

 知網情感詞典下載地址:- http://www.keenage.com/html/c_bulletin_2007.htm

 

 

 

 

 

 

 3、原理介紹

3.1 基於BosonNLP情感分析原理

基於BosonNLP情感詞典的情感分析較為簡單。首先,需要對文字進行分句、分詞,本文選擇的分詞工具為哈工大的pyltp。其次,將分詞好的列表資料對應BosonNLp詞典進行逐個匹配,並記錄匹配到的情感詞分值。最後,統計計算分值總和,如果分值大於0,表示情感傾向為積極的;如果小於0,則表示情感傾向為消極的。原理框圖如下:

 

 

 

3.2 基於BosonNLP情感分析程式碼:

# -*- coding:utf-8 -*-
import pandas as pd
import jieba

#基於波森情感詞典計算情感值
def getscore(text):
    df = pd.read_table(r"BosonNLP_dict\BosonNLP_sentiment_score.txt", sep=" ", names=['key', 'score'])
    key = df['key'].values.tolist()
    score = df['score'].values.tolist()
    # jieba分詞
    segs = jieba.lcut(text,cut_all = False) #返回list
    # 計算得分
    score_list = [score[key.index(x)] for x in segs if(x in key)]
    return sum(score_list)

#讀取檔案
def read_txt(filename):
    with open(filename,'r',encoding='utf-8')as f:
        txt = f.read()
    return txt
#寫入檔案
def write_data(filename,data):
    with open(filename,'a',encoding='utf-8')as f:
        f.write(data)


if __name__=='__main__':
    text = read_txt('test_data\微博.txt')
    lists  = text.split('\n')

    # al_senti = ['無','積極','消極','消極','中性','消極','積極','消極','積極','積極','積極',
    #             '無','積極','積極','中性','積極','消極','積極','消極','積極','消極','積極',
    #             '無','中性','消極','中性','消極','積極','消極','消極','消極','消極','積極'
    #             ]
    al_senti = read_txt(r'test_data\人工情感標註.txt').split('\n')
    i = 0
    for list in lists:
        if list  != '':
            # print(list)
            sentiments = round(getscore(list),2)
            #情感值為正數,表示積極;為負數表示消極
            print(list)
            print("情感值:",sentiments)
            print('人工標註情感傾向:'+al_senti[i])
            if sentiments > 0:
                print("機器標註情感傾向:積極\n")
                s = "機器判斷情感傾向:積極\n"
            else:
                print('機器標註情感傾向:消極\n')
                s = "機器判斷情感傾向:消極"+'\n'
            sentiment = '情感值:'+str(sentiments)+'\n'
            al_sentiment= '人工標註情感傾向:'+al_senti[i]+'\n'
            #檔案寫入
            filename = 'result_data\BosonNLP情感分析結果.txt'
            write_data(filename,'情感分析文字:')
            write_data(filename,list+'\n') #寫入待處理文字
            write_data(filename,sentiment) #寫入情感值
            write_data(filename,al_sentiment) #寫入機器判斷情感傾向
            write_data(filename,s+'\n') #寫入人工標註情感
            i = i+1

相關檔案:

BosonNLp情感詞典下載地址:https://bosonnlp.com/dev/resource

微博語料:連結:https://pan.baidu.com/s/1Pskzw7bg9qTnXD_QKF-4sg   提取碼:15bu

輸出結果:

 

 3.3 基於知網情感詞典的情感挖掘原理

基於知網情感詞典的情感分析原理分為以下幾步:

1、首先,需要對文字分句,分句,得到分詞分句後的文字語料,並將結果與哈工大的停用詞表比對,去除停用詞;

2、其次,對每一句話進行情感分析,分析的方法主要為:判斷這段話中的情感詞數目,含有積極詞,則積極詞數目加1,含有消極詞,則消極詞數目加1。並且再統計的過程中還需要判斷該情感詞前面是否存在程度副詞,如果存在,則需要根據程度副詞的種類賦予不同的權重,乘以情感詞數。如果句尾存在?!等符號,則情感詞數目增加一定值,因為!與?這類的標點往往表示情感情緒的加強,因此需要進行一定處理。

3、接著統計計算整段話的情感值(積極詞值-消極詞值),得到該段文字的情感傾向。

4、最後,統計每一段的情感值,相加得到文章的情感值。

整體流程框圖如下:

 

3.4 基於知網情感詞典的情感分析程式碼:

import pyltp
from pyltp import Segmentor
from pyltp import SentenceSplitter
from pyltp import Postagger
import numpy as np

#讀取檔案,檔案讀取函式
def read_file(filename):
    with  open(filename, 'r',encoding='utf-8')as f:
        text = f.read()
        #返回list型別資料
        text = text.split('\n')
    return text

#將資料寫入檔案中
def write_data(filename,data):
    with open(filename,'a',encoding='utf-8')as f:
        f.write(str(data))

#文字分句
def cut_sentence(text):
    sentences = SentenceSplitter.split(text)
    sentence_list = [ w for w in sentences]
    return sentence_list

#文字分詞
def tokenize(sentence):
    #載入模型
    segmentor = Segmentor()  # 初始化例項
    # 載入模型
    segmentor.load(r'E:\tool\python\Lib\site-packages\pyltp-0.2.1.dist-info\ltp_data\cws.model')
    # 產生分詞,segment分詞函式
    words = segmentor.segment(sentence)
    words = list(words)
    # 釋放模型
    segmentor.release()
    return words

#詞性標註
def postagger(words):
    # 初始化例項
    postagger = Postagger()
    # 載入模型
    postagger.load(r'E:\tool\python\Lib\site-packages\pyltp-0.2.1.dist-info\ltp_data\pos.model')
    # 詞性標註
    postags = postagger.postag(words)
    # 釋放模型
    postagger.release()
    #返回list
    postags = [i for i in postags]
    return postags

# 分詞,詞性標註,詞和詞性構成一個元組
def intergrad_word(words,postags):
    #拉鍊演算法,兩兩匹配
    pos_list = zip(words,postags)
    pos_list = [ w for w in pos_list]
    return pos_list

#去停用詞函式
def del_stopwords(words):
    # 讀取停用詞表
    stopwords = read_file(r"test_data\stopwords.txt")
    # 去除停用詞後的句子
    new_words = []
    for word in words:
        if word not in stopwords:
            new_words.append(word)
    return new_words

# 獲取六種權值的詞,根據要求返回list,這個函式是為了配合Django的views下的函式使用
def weighted_value(request):
    result_dict = []
    if request == "one":
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\degree_dict\most.txt")
    elif request == "two":
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\degree_dict\very.txt")
    elif request == "three":
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\degree_dict\more.txt")
    elif request == "four":
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\degree_dict\ish.txt")
    elif request == "five":
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\degree_dict\insufficiently.txt")
    elif request == "six":
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\degree_dict\inverse.txt")
    elif request == 'posdict':
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\emotion_dict\pos_all_dict.txt")
    elif request == 'negdict':
        result_dict = read_file(r"E:\學習筆記\NLP學習\NLP code\情感分析3\emotion_dict\neg_all_dict.txt")
    else:
        pass
    return result_dict

print("reading sentiment dict .......")
#讀取情感詞典
posdict = weighted_value('posdict')
negdict = weighted_value('negdict')
# 讀取程度副詞詞典
# 權值為2
mostdict = weighted_value('one')
# 權值為1.75
verydict = weighted_value('two')
# 權值為1.50
moredict = weighted_value('three')
# 權值為1.25
ishdict = weighted_value('four')
# 權值為0.25
insufficientdict = weighted_value('five')
# 權值為-1
inversedict = weighted_value('six')

#程度副詞處理,對不同的程度副詞給予不同的權重
def match_adverb(word,sentiment_value):
    #最高階權重為
    if word in mostdict:
        sentiment_value *= 8
    #比較級權重
    elif word in verydict:
        sentiment_value *= 6
    #比較級權重
    elif word in moredict:
        sentiment_value *= 4
    #輕微程度詞權重
    elif word in ishdict:
        sentiment_value *= 2
    #相對程度詞權重
    elif word in insufficientdict:
        sentiment_value *= 0.5
    #否定詞權重
    elif word in inversedict:
        sentiment_value *= -1
    else:
        sentiment_value *= 1
    return sentiment_value

#對每一條微博打分
def single_sentiment_score(text_sent):
    sentiment_scores = []
    #對單條微博分句
    sentences = cut_sentence(text_sent)
    for sent in sentences:
        #檢視分句結果
        # print('分句:',sent)
        #分詞
        words = tokenize(sent)
        seg_words = del_stopwords(words)
        #i,s 記錄情感詞和程度詞出現的位置
        i = 0   #記錄掃描到的詞位子
        s = 0   #記錄情感詞的位置
        poscount = 0 #記錄積極情感詞數目
        negcount = 0 #記錄消極情感詞數目
        #逐個查詢情感詞
        for word in seg_words:
            #如果為積極詞
            if word in posdict:
                poscount += 1  #情感詞數目加1
            #在情感詞前面尋找程度副詞
                for w in seg_words[s:i]:
                    poscount = match_adverb(w,poscount)
                s = i+1 #記錄情感詞位置
            # 如果是消極情感詞
            elif word in negdict:
                negcount +=1
                for w in seg_words[s:i]:
                    negcount = match_adverb(w,negcount)
                s = i+1
            #如果結尾為感嘆號或者問號,表示句子結束,並且倒序查詢感嘆號前的情感詞,權重+4
            elif word =='!' or  word =='!' or word =='?' or word == '?':
                for w2 in seg_words[::-1]:
                    #如果為積極詞,poscount+2
                    if w2 in posdict:
                        poscount += 4
                        break
                    #如果是消極詞,negcount+2
                    elif w2 in negdict:
                        negcount += 4
                        break
            i += 1 #定位情感詞的位置
        #計算情感值
        sentiment_score = poscount - negcount
        sentiment_scores.append(sentiment_score)
        #檢視每一句的情感值
        # print('分句分值:',sentiment_score)
    sentiment_sum = 0
    for s in sentiment_scores:
        #計算出一條微博的總得分
        sentiment_sum +=s
    return sentiment_sum

# 分析test_data.txt 中的所有微博,返回一個列表,列表中元素為(分值,微博)元組
def run_score(contents):
    # 待處理資料
    scores_list = []
    for content in contents:
        if content !='':
            score = single_sentiment_score(content)  # 對每條微博呼叫函式求得打分
            scores_list.append((score, content)) # 形成(分數,微博)元組
    return scores_list

#主程式
if __name__ == '__main__':
    print('Processing........')
    #測試
    # sentence = '要怎麼說呢! 我需要的戀愛不是現在的樣子, 希望是能互相鼓勵的勉勵, 你現在的樣子讓我覺得很困惑。 你到底能不能陪我一直走下去, 你是否有決心?是否你看不慣我?你是可以隨意的生活,但是我的未來我耽誤不起!'
    # sentence = '轉有用嗎?這個事本來就是要全社會共同努力的,公交公司有沒有培訓到位?公交車上地鐵站內有沒有放足夠的宣傳標語?我現在轉一下微博,沒有多大的意義。'
    sentences = read_file(r'test_data\微博.txt')
    scores = run_score(sentences)
    #人工標註情感詞典
    man_sentiment = read_file(r'test_data\人工情感標註.txt')
    al_sentiment = []
    for score in scores:
        print('情感分值:',score[0])
        if score[0] < 0:
            print('情感傾向:消極')
            s = '消極'
        elif score[0] == 0:
            print('情感傾向:中性')
            s = '中性'
        else:
            print('情感傾向:積極')
            s = '積極'
        al_sentiment.append(s)
        print('情感分析文字:',score[1])
    i = 0
    #寫入檔案中
    filename = r'result_data\result_data.txt'
    for score in scores:
        write_data(filename, '情感分析文字:{}'.format(str(score[1]))+'\n') #寫入情感分析文字
        write_data(filename,'情感分值:{}'.format(str(score[0]))+'\n') #寫入情感分值
        write_data(filename,'人工標註情感:{}'.format(str(man_sentiment[i]))+'\n') #寫入人工標註情感
        write_data(filename, '機器情感標註:{}'.format(str(al_sentiment[i]))+'\n') #寫入機器情感標註
        write_data(filename,'\n')
        i +=1
    print('succeed.......')

 

 輸出結果:

 

4、小結

 本次的情感分析程式完成簡單的情感傾向判斷,準確率上基於BosonNLP的情感分析較低,其情感分析準確率為:56.67%;而基於知網情感詞典的情感分析準確率達到90%,效果上還是不錯的。但是,這兩個程式都還只是情感分析簡單使用,並未涉及到更深奧的演算法,如果想要更加精確,或者再更大樣本中獲得更高精度,這兩個情感分析模型還是不夠的。但是用來練習學習還是不錯的選擇。要想更深入的理解和弄得情感分析,還需要繼續學習。

 

PS:需要基於知網情感詞典的情感分析詞典資料,可以在評論中留下你的郵箱,我發給你。

&n