徹底基於情感詞典的文本情感分析

目前情感分析在中文天然語言處理中比較火熱,不少場景下,咱們都須要用到情感分析。好比,作金融產品量化交易,須要根據爬取的輿論數據來分析政策和輿論對股市或者基金期貨的態度;電商交易,根據買家的評論數據,來分析商品的預售率等等。javascript

下面咱們經過如下幾點來介紹中文天然語言處理情感分析:java

  1. 中文情感分析方法簡介;
  2. SnowNLP 快速進行評論數據情感分析;
  3. 基於標註好的情感詞典來計算情感值;
  4. pytreebank 繪製情感樹;
  5. 股吧數據情感分類。

中文情感分析方法簡介

情感傾向可認爲是主體對某一客體主觀存在的心裏喜惡,內在評價的一種傾向。它由兩個方面來衡量:一個情感傾向方向,一個是情感傾向度。python

enter image description here

目前,情感傾向分析的方法主要分爲兩類:一種是基於情感詞典的方法;一種是基於機器學習的方法,如基於大規模語料庫的機器學習。前者須要用到標註好的情感詞典;後者則須要大量的人工標註的語料做爲訓練集,經過提取文本特徵,構建分類器來實現情感的分類。git

文本情感分析的分析粒度能夠是詞語、句子、段落或篇章。github

段落篇章級情感分析主要是針對某個主題或事件進行情感傾向判斷,通常須要構建對應事件的情感詞典,如電影評論的分析,須要構建電影行業本身的情感詞典,這樣效果會比通用情感詞典更好;也能夠經過人工標註大量電影評論來構建分類器。句子級的情感分析大多經過計算句子裏包含的全部情感詞的值來獲得。算法

篇章級的情感分析,也能夠經過聚合篇章中全部的句子的情感傾向來計算得出。所以,針對句子級的情感傾向分析,既能解決短文本的情感分析,同時也是篇章級文本情感分析的基礎。json

中文情感分析的一些難點,好比句子是由詞語根據必定的語言規則構成的,應該把句子中詞語的依存關係歸入到句子情感的計算過程當中去,不一樣的依存關係,進行情感傾向計算是不同的。文檔的情感,根據句子對文檔的重要程度賦予不一樣權重,調整其對文檔情感的貢獻程度等。bash

SnowNLP 快速進行評論數據情感分析

若是有人問,有沒有比較快速簡單的方法能判斷一句話的情感傾向,那麼 SnowNLP 庫就是答案。app

SnowNLP 主要能夠進行中文分詞、詞性標註、情感分析、文本分類、轉換拼音、繁體轉簡體、提取文本關鍵詞、提取摘要、分割句子、文本類似等。dom

須要注意的是,用 SnowNLP 進行情感分析,官網指出進行電商評論的準確率較高,實際上是由於它的語料庫主要是電商評論數據,可是能夠本身構建相關領域語料庫,替換單一的電商評論語料,準確率也挺不錯的。

1. SnowNLP 安裝。

(1) 使用 pip 安裝:

pip install snownlp==0.11.1

(2)使用 Github 源碼安裝。

首先,下載 SnowNLP 的 Github 源碼並解壓,在解壓目錄,經過下面命令安裝:

python  setup.py install

以上方式,二選一安裝完成以後,就能夠引入 SnowNLP 庫使用了。

from snownlp import SnowNLP

2. 評論語料獲取情感值。

首先,SnowNLP 對情感的測試值爲0到1,值越大,說明情感傾向越積極。下面咱們經過 SnowNLP 測試在京東上找的好評、中評、差評的結果。

首先,引入 SnowNLP 庫:

from snownlp import SnowNLP

(1) 測試一條京東的好評數據:

SnowNLP(u'本本已收到,體驗仍是很好,功能方面我不瞭解,只看外觀仍是很不錯很薄,很輕,也有質感。').sentiments

獲得的情感值很高,說明買家對商品比較承認,情感值爲:

0.999950702449061

(2)測試一條京東的中評數據:

SnowNLP(u'屏幕分辨率通常,送了個極醜的鼠標。').sentiments

獲得的情感值通常,說明買家對商品見解通常,甚至不喜歡,情感值爲:

0.03251402883400323

(3)測試一條京東的差評數據:

SnowNLP(u'不好的一次購物體驗,細節作得極差了,還有發熱有點嚴重啊,散熱不行,用起來就是燙得厲害,很垃圾!!!').sentiments

獲得的情感值通常,說明買家對商品不承認,存在退貨嫌疑,情感值爲:

0.0036849517156107847

以上就完成了簡單快速的情感值計算,對評論數據是否是很好用呀!!!

使用 SnowNLP 來計算情感值,官方推薦的是電商評論數據計算準確度比較高,難道非評論數據就不能使用 SnowNLP 來計算情感值了嗎?固然不是,雖然 SnowNLP 默認提供的模型是用評論數據訓練的,可是它還支持咱們根據現有數據訓練本身的模型。

首先咱們來看看自定義訓練模型的源碼 Sentiment 類,代碼定義以下:

class Sentiment(object): def __init__(self): self.classifier = Bayes() def save(self, fname, iszip=True): self.classifier.save(fname, iszip) def load(self, fname=data_path, iszip=True): self.classifier.load(fname, iszip) def handle(self, doc): words = seg.seg(doc) words = normal.filter_stop(words) return words def train(self, neg_docs, pos_docs): data = [] for sent in neg_docs: data.append([self.handle(sent), 'neg']) for sent in pos_docs: data.append([self.handle(sent), 'pos']) self.classifier.train(data) def classify(self, sent): ret, prob = self.classifier.classify(self.handle(sent)) if ret == 'pos': return prob return 1-prob

經過源代碼,咱們能夠看到,可使用 train方法訓練數據,並使用 save 方法和 load 方法保存與加載模型。下面訓練本身的模型,訓練集 pos.txt 和 neg.txt 分別表示積極和消極情感語句,兩個 TXT 文本中每行表示一句語料。

下面代碼進行自定義模型訓練和保存:

from snownlp import sentiment sentiment.train('neg.txt', 'pos.txt') sentiment.save('sentiment.marshal')

基於標註好的情感詞典來計算情感值

這裏咱們使用一個行業標準的情感詞典——玻森情感詞典,來自定義計算一句話、或者一段文字的情感值。

整個過程以下:

  1. 加載玻森情感詞典;
  2. jieba 分詞;
  3. 獲取句子得分。

首先引入包:

import pandas as pd import jieba

接下來加載情感詞典:

df = pd.read_table("bosonnlp//BosonNLP_sentiment_score.txt",sep= " ",names=['key','score'])

查看一下情感詞典前5行:

enter image description here

將詞 key 和對應得分 score 轉成2個 list 列表,目的是找到詞 key 的時候,能對應獲取到 score 值:

key = df['key'].values.tolist() score = df['score'].values.tolist()

定義分詞和統計得分函數:

def getscore(line): segs = jieba.lcut(line)  #分詞
    score_list  = [score[key.index(x)] for x in segs if(x in key)] return  sum(score_list)  #計算得分

最後來進行結果測試:

line = "今每天氣很好,我很開心"
print(round(getscore(line),2)) line = "今天下雨,心情也受到影響。"
print(round(getscore(line),2))

得到的情感得分保留2位小數:

5.26

-0.96

pytreebank 繪製情感樹

1. 安裝 pytreebank。

在 Github 上下載 pytreebank 源碼,解壓以後,進入解壓目錄命令行,執行命令:

python setup.py install

最後經過引入命令,判斷是否安裝成功:

import pytreebank

提示,若是在 Windows 下安裝以後,報錯誤:

UnicodeDecodeError: 'gbk' codec can't decode byte 0x92 in position 24783: illegal multibyte sequence 

這是因爲編碼問題引發的,能夠在安裝目錄下報錯的文件中報錯的代碼地方加個encoding='utf-8' 編碼:

import_tag( "script", contents=format_replacements(open(scriptname,encoding='utf-8').read(), replacements), type="text/javascript" )

2. 繪製情感樹。

首先引入 pytreebank 包:

import pytreebank

而後,加載用來可視化的 JavaScript 和 CSS 腳本:

pytreebank.LabeledTree.inject_visualization_javascript()

繪製情感樹,把句子首先進行組合再繪製圖形:

line = '(4 (0 你) (3 (2 是) (3 (3 (3 誰) (2 的)) (2 誰))))' pytreebank.create_tree_from_string(line).display()

獲得的情感樹以下:

enter image description here

股吧數據情感分類

歷經89天的煎熬以後,7月15日中興終於盼來了解禁,在此首先恭喜中興,解禁了,但願再踏征程。

但在7月15日以前,隨着中美貿易戰不斷升級,中興股價又上演了一場「跌跌不休」的慘狀,我以中美貿易戰背景下中興通信在股吧解禁前一段時間的評論數據,來進行情感數據人工打標籤和分類。其中,把消極 、中性 、積極分別用0、一、2來表示。

整個文本分類流程主要包括如下6個步驟:

  • 中文語料;
  • 分詞;
  • 複雜規則;
  • 特徵向量;
  • 算法建模;
  • 情感分析。

enter image description here

本次分類算法採用 CNN,首先引入須要的包:

import pandas as pd import numpy as np import jieba import random import keras from keras.preprocessing import sequence from keras.models import Sequential from keras.layers import Dense, Dropout, Activation from keras.layers import Embedding from keras.layers import Conv1D, GlobalMaxPooling1D from keras.datasets import imdb from keras.models import model_from_json from keras.utils import np_utils import matplotlib.pyplot as plt

繼續引入停用詞和語料文件:

dir = "D://ProgramData//PythonWorkSpace//chat//chat8//" stopwords=pd.read_csv(dir +"stopwords.txt",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8') stopwords=stopwords['stopword'].values df_data1 = pd.read_csv(dir+"data1.csv",encoding='utf-8') df_data1.head()

下圖展現數據的前5行:

enter image description here

接着進行數據預處理,把消極、中性、積極分別爲0、一、2的預料分別拿出來:

#把內容有缺失值的刪除
df_data1.dropna(inplace=True) #抽取文本數據和標籤
data_1 = df_data1.loc[:,['content','label']] #把消極 中性 積極分別爲0、一、2的預料分別拿出來
data_label_0 = data_1.loc[data_1['label'] ==0,:] data_label_1 = data_1.loc[data_1['label'] ==1,:] data_label_2 = data_1.loc[data_1['label'] ==2,:]

接下來,定義中文分詞函數:

#定義分詞函數
def preprocess_text(content_lines, sentences, category): for line in content_lines: try: segs=jieba.lcut(line) segs = filter(lambda x:len(x)>1, segs) segs = [v for v in segs if not str(v).isdigit()]#去數字
            segs = list(filter(lambda x:x.strip(), segs)) #去左右空格
            segs = filter(lambda x:x not in stopwords, segs) temp = " ".join(segs) if(len(temp)>1): sentences.append((temp, category)) except Exception: print(line) continue

生成訓練的分詞數據,並進行打散,使其分佈均勻:

#獲取數據
data_label_0_content = data_label_0['content'].values.tolist() data_label_1_content = data_label_1['content'].values.tolist() data_label_2_content = data_label_2['content'].values.tolist() #生成訓練數據
sentences = [] preprocess_text(data_label_0_content, sentences, 0) preprocess_text(data_label_1_content, sentences, 1) preprocess_text(data_label_2_content, sentences,2) #咱們打亂一下順序,生成更可靠的訓練集
random.shuffle(sentences)

對數據集進行切分,按照訓練集合測試集7:3的比例:

#因此把原數據集分紅訓練集的測試集,我們用sklearn自帶的分割函數。
from sklearn.model_selection import train_test_split x, y = zip(*sentences) x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3,random_state=1234)

而後,對特徵構造詞向量:

#抽取特徵,咱們對文本抽取詞袋模型特徵
from sklearn.feature_extraction.text import CountVectorizer vec = CountVectorizer( analyzer='word', #tokenise by character ngrams
    max_features=4000,  #keep the most common 1000 ngrams
) vec.fit(x_train)

定義模型參數:

# 設置參數
max_features = 5001 maxlen = 100 batch_size = 32 embedding_dims = 50 filters = 250 kernel_size = 3 hidden_dims = 250 epochs = 10 nclasses = 3

輸入特徵轉成 Array 和標籤處理,打印訓練集和測試集的 shape:

x_train = vec.transform(x_train) x_test = vec.transform(x_test) x_train = x_train.toarray() x_test = x_test.toarray() y_train = np_utils.to_categorical(y_train,nclasses) y_test = np_utils.to_categorical(y_test,nclasses) x_train = sequence.pad_sequences(x_train, maxlen=maxlen) x_test = sequence.pad_sequences(x_test, maxlen=maxlen) print('x_train shape:', x_train.shape) print('x_test shape:', x_test.shape)

定義一個繪製 Loss 曲線的類:

class LossHistory(keras.callbacks.Callback): def on_train_begin(self, logs={}): self.losses = {'batch':[], 'epoch':[]} self.accuracy = {'batch':[], 'epoch':[]} self.val_loss = {'batch':[], 'epoch':[]} self.val_acc = {'batch':[], 'epoch':[]} def on_batch_end(self, batch, logs={}): self.losses['batch'].append(logs.get('loss')) self.accuracy['batch'].append(logs.get('acc')) self.val_loss['batch'].append(logs.get('val_loss')) self.val_acc['batch'].append(logs.get('val_acc')) def on_epoch_end(self, batch, logs={}): self.losses['epoch'].append(logs.get('loss')) self.accuracy['epoch'].append(logs.get('acc')) self.val_loss['epoch'].append(logs.get('val_loss')) self.val_acc['epoch'].append(logs.get('val_acc')) def loss_plot(self, loss_type): iters = range(len(self.losses[loss_type])) plt.figure() # acc
        plt.plot(iters, self.accuracy[loss_type], 'r', label='train acc') # loss
        plt.plot(iters, self.losses[loss_type], 'g', label='train loss') if loss_type == 'epoch': # val_acc
            plt.plot(iters, self.val_acc[loss_type], 'b', label='val acc') # val_loss
            plt.plot(iters, self.val_loss[loss_type], 'k', label='val loss') plt.grid(True) plt.xlabel(loss_type) plt.ylabel('acc-loss') plt.legend(loc="upper right") plt.show()

而後,初始化上面類的對象,並做爲模型的回調函數輸入,訓練模型:

history = LossHistory() print('Build model...') model = Sequential() model.add(Embedding(max_features, embedding_dims, input_length=maxlen)) model.add(Dropout(0.5)) model.add(Conv1D(filters, kernel_size, padding='valid', activation='relu', strides=1)) model.add(GlobalMaxPooling1D()) model.add(Dense(hidden_dims)) model.add(Dropout(0.5)) model.add(Activation('relu')) model.add(Dense(nclasses)) model.add(Activation('softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(x_test, y_test),callbacks=[history])

獲得的模型迭代次數爲10輪的訓練過程:

enter image description here

最後繪製 Loss 圖像:

enter image description here

關於本次分類,這裏重點討論的一個知識點就是數據分佈不均勻的狀況,咱們都知道,本次貿易戰中興公司受影響很大,致使整個股票價格處於下跌趨勢,因此整個輿論上,大多數評論都是消極的態度,致使數據分佈極不均勻。

那數據分佈不均勻通常怎麼處理呢?從如下幾個方面考慮:

  • 數據採樣,包括上採樣、下采樣和綜合採樣;

  • 改變分類算法,在傳統分類算法的基礎上對不一樣類別採起不一樣的加權方式,使得模型更看重少數類;

  • 採用合理的性能評價指標;

  • 代價敏感。

總結,本文經過第三方、基於詞典等方式計算中文文本情感值,以及經過情感樹來進行可視化,然而這些內容只是情感分析的入門知識,情感分析還涉及句法依存等,最後經過一個 CNN 分類模型,提供一種有監督的情感分類思路。

相關文章
相關標籤/搜索