【機器學習】10:樸素貝葉斯做文本分類

前言:

在文本分類中,垃圾郵件分類是個二分類任務,比較容易說明文本分類的原理,所以以下以垃圾郵件分類爲例,講述使用樸素貝葉斯算法做評論分類的使用方法及過程,後面有本篇代碼鏈接。
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
這裏是【機器學習】9:樸素貝葉斯算法原理,對貝葉斯原理不清楚的夥伴,可以自主學習。
---------------------------------------------------------------------------------------------------------------------
本篇博客所用到的代碼以及《譚鬆波酒店評論語料》都在這裏可以下載
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------

一、樸素貝葉斯如何應用於垃圾郵件分類

1.1、數據準備階段:

  1. 在郵件識別中,我們已知有一個訓練樣本空間集C=(X1,X2,...,Xn)C=(X_1,X_2,...,X_n),每條樣本數據具有多條屬性Xi=(xi1,xi2,...,xim)X_i=(x_{i1},x_{i2},...,x_{im})
  2. 樣本空間所有類別標籤: Y=(y1,y2,...,ym)Y=(y_1,y_2,...,y_m);樣本空間每一條樣本XX都有一個類別標籤yy對應;
  3. 用結巴分詞將每條樣本XX切成分詞的形式:X=(x1,x2,...,xk)X=(x_1,x_2,...,x_k)

比如我們已知的兩條樣本如下:<樣本,標籤>的形式:

  • X1X_1:需要|爲|企業|開具|發票,請|聯繫|我。 ——垃圾郵件
  • X2X_2:附件|是|我|做的|報表,如果|可行|,請|批示。 ——非垃圾郵件

---------------------------------------------------------------------------------------------------------------------

1.2、數據處理階段:詞袋模型

詞袋模型就是將樣本空間所有的樣本先切詞、再去重後得到的詞語大集合,配合one-hot編碼格式產生如下的詞語模型:
在這裏插入圖片描述

  • 青色:X1,X2,...X_1,X_2,...每一條都是一個樣本數據;
  • 藍色:就是我們將樣本集CC中所有的樣本用結巴分詞切詞並去重得到的大詞袋,詞袋Xall=(x1,x2,..,xk,..,xn)X_{all}=(x_1,x_2,..,x_k,..,x_n)
  • 橙色:每行的0-1數據就是該樣本XXone-hot編碼;

---------------------------------------------------------------------------------------------------------------------

1.3、貝葉斯計算概率——訓練階段:

依照訓練樣本集C=(X1,X2,...,Xn)C=(X_1,X_2,...,X_n)中的數據:

計算1:垃圾郵件的佔比、非垃圾郵件的佔比:

  • P(C=yi)P(C=y_i)yiy_i \in()(是,不是)

計算2:詞袋中每個詞,在“是/非”垃圾郵件中出現的概率:

  • P(x1yi)P(x_1|y_i)P(x2yi)P(x_2|y_i),…,P(xkyi)P(x_k|y_i),…,P(xnyi)P(x_n|y_i)yiy_i \in()(是,不是)

---------------------------------------------------------------------------------------------------------------------

1.4、貝葉斯計算概率——測試階段:

有一測試數據KK轉化爲該詞袋模型的one-hot編碼爲:K=(x1,x2,...,xl)K=(x_1,x_2,...,x_l),計算max(P(x1,x2,...,xl)P(x1,x2,...,xl))max(P(x_1,x_2,...,x_l|是),P(x_1,x_2,...,x_l|不是)),哪個標籤的概率大就歸入哪個類。

---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------

二、舉例:樸素貝葉斯做垃圾郵件分類

2.1、數據準備,數據處理階段

在這裏插入圖片描述
有一數據集如上,樣本集CC一共切出14個詞,組成的詞袋如下:

  • Xall=X_{all}=[‘下午’, ‘酒吧’, ‘開會’, ‘開發票’, ‘有償’, ‘回覆’, ‘4’, ‘信息’, ‘請’, ‘基本’, ‘填寫’, ‘收到’, ‘夜店’, ‘點’]

轉化得到的one-hot編碼矩陣如下:(標籤——1:是垃圾郵件; 0:不是垃圾郵件)
在這裏插入圖片描述
---------------------------------------------------------------------------------------------------------------------

2.2、貝葉斯計算概率——訓練階段:

計算1:垃圾郵件的佔比、非垃圾郵件的佔比:(已做拉普拉斯平滑)

  • P(C=)=P(C=是)=2+15+22+1 \over 5+2P(C=)=P(C=不是)=3+15+23+1 \over 5+2

計算2:詞袋中每個詞,在“是/非”垃圾郵件中出現的概率如下:(已做拉普拉斯平滑)
在這裏插入圖片描述
舉例,“下午”在垃圾郵件的概率=0.25、在非垃圾郵件的概率=0.4是如何計算的:

  • 訓練集中共有2條垃圾郵件,“下午”在垃圾郵件中出現的次數爲0,出現的概率P(下午|是)=0/2,用拉普拉斯修正後=(0+1)/(2+2)=0.25;
  • 訓練集中共有3條非垃圾郵件,“下午”在非垃圾郵件中出現的次數爲1,出現的概率P(下午|不是)=1/3,用拉普拉斯修正後=(1+1)/(3+2)=0.4;

重要說明:

從上表中可以發現,“下午”或其他一個詞,在垃圾郵件中出現的概率 + 在非垃圾郵件中出現的概率並不一定等於1,這說明:同一個詞語在“是/非”兩個標籤陣營下並不是完全對立的事件,換句話說11-P(xk)P(x_k|不是)不一定等於 P(xk)P(x_k|是)。——這在下面樣本測試階段的時候就能知道它的重要性了。

---------------------------------------------------------------------------------------------------------------------

2.3、貝葉斯計算概率——測試階段:

測試:Xnow=X_{now}=“請填寫開發票信息”–>“請|填寫|開發票|信息”–>[0,0,0,1,0,0,0,1,1,0,1,0,0,0]

XnowX_{now}是垃圾郵件的前提下,新樣本出現的概率:

  • P(Xnow)=P(X_{now}|是)=P([x1,x2,...,x14]1)=P([x_1,x_2,...,x_{14}]|1)=(1P(x11))(1P(x21))(1P(x31))P(x41)...(1-P(x_1|1))*(1-P(x_2|1))*(1-P(x_3|1))*P(x_4|1)*...

XnowX_{now}不是垃圾郵件前提下,新樣本出現的概率:

  • P(Xnow)=P(X_{now}|不是)=P([x1,x2,...,x14]0)=P([x_1,x_2,...,x_{14}]|0)=(1P(x10))(1P(x20))(1P(x30))P(x40)...(1-P(x_1|0))*(1-P(x_2|0))*(1-P(x_3|0))*P(x_4|0)*...

最後哪個概率大,就把新樣本分屬到該類中。

說明:

  1. 如果xix_i在測試語句中出現了,就用其本身的條件概率,比如x4,x8,x9,x11x_4,x_8,x_9,x_{11}, 如果xix_i在測試語句中沒有出現,就用(1-本身的條件概率)——(1-本身的條件概率)纔是對立事件,因爲(1P(x11))(1-P(x_1|1))不一定等於P(x10)P(x_1|0),所以P(Xnow)=P(X_{now}|是)=P([x1,x2,...,x14]1)=P([x_1,x_2,...,x_{14}]|1)=P(x10)P(x20)P(x30)P(x41)...P(x_1|0)*P(x_2|0)*-P(x_3|0)*P(x_4|1)*...,這種計算方式是錯誤的,請務必知悉;
  2. 一般在計算過程中,爲防止數值下逸,會在計算每個xix_i的概率後做log()log()處理。也就是說上式最終形態應該是:P(Xnow)=P(X_{now}|是)=P([x1,x2,...,x14]1)=P([x_1,x_2,...,x_{14}]|1)=log(1P(x11))log(1P(x21))log(1P(x31))log(P(x41))...log(1-P(x_1|1))*log(1-P(x_2|1))*log(1-P(x_3|1))*log(P(x_4|1))*...

---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------

三、樸素貝葉斯做文本分類

---------------------------------------------------------------------------------------------------------------------
本篇博客所用到的代碼以及《譚鬆波酒店評論語料》都在這裏可以下載
---------------------------------------------------------------------------------------------------------------------
從《譚鬆波酒店評論語料》截取的部分好評、差評數據如下:
在這裏插入圖片描述在這裏插入圖片描述

---------------------------------------------------------------------------------------------------------------------

3.1、數據預處理

數據預處理階段包括:整合數據生成樣本空間、生成詞袋、統計詞頻生成模型

# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing  CSDN address:https://blog.csdn.net/zzZ_CMing
# -*- 2019/04/24; 15:19
# -*- python3.6
import pandas as pd
import numpy as np
import jieba
import os

from sklearn.feature_extraction.text import CountVectorizer  # 詞頻計數
from sklearn.feature_extraction.text import TfidfVectorizer  # tf-idf 模塊


def get_sent_readin_data(outputfile,input_fold,label_name):
    """
    讀取單個文件整合到一個文件中
    :param outputfile: 輸出的大文件地址
    :param input_fold: 輸入的單個小文件地址
    :param label_name: 標籤
    :return: 整合後的兩個大文件
    """
    file_name_list = [k for i,j,k in os.walk(input_fold)][0]
    neg_all = open(outputfile,'w', encoding="UTF-8")
    for ifile in file_name_list:
        with open(input_fold+ '%s'%ifile, 'r', encoding="UTF-8") as freaddata:
            lines = freaddata.readlines()
            writeline = ''.join([i.strip() for i in lines])
            tlines = label_name + '\t' + writeline + '\n'
            neg_all.write(tlines)
    neg_all.close()
    return 'Done!'


def get_neg_pos_data():
    """
    整合正負例文本
    :return: 返回正例樣本和負例樣本
    """
    input_fold1='samples/neg/'
    outputfile1='samples/neg_all.txt'
    label_name1='neg'
    get_sent_readin_data(outputfile1, input_fold1, label_name1)
    input_fold2='samples/pos/'
    outputfile2='samples/pos_all.txt'
    label_name2='pos'
    get_sent_readin_data(outputfile2, input_fold2, label_name2)
    return outputfile1, outputfile2


neg_outfile, pos_outfile = get_neg_pos_data()
neg_data = pd.read_table(neg_outfile, names=['label','chat'])
pos_data = pd.read_table(pos_outfile, names=['label','chat'])
neg_data['labelnum']=-1
pos_data['labelnum']=1

---------------------------------------------------------------------------------------------------------------------

# [1]:查看樣本空間
all_data = pd.concat([neg_data, pos_data])
#print("all_data=", all_data.head())

在這裏插入圖片描述

---------------------------------------------------------------------------------------------------------------------

# [2]:生成詞袋
corpus=[' '.join(jieba.lcut(all_data.iloc[i,1])) for i in range(len(all_data))]
# print("corpus=", corpus)

在這裏插入圖片描述

---------------------------------------------------------------------------------------------------------------------

# [3]:計數統計,tf-idf模塊
vectorizer = CountVectorizer()
corpusTotoken_count = vectorizer.fit_transform(corpus).todense()
vectorizer = TfidfVectorizer()
corpusTotoken_tfidf = vectorizer.fit_transform(corpus).todense()
# print("corpusTotoken_count=", corpusTotoken_count)
# print("corpusTotoken_tfidf=", corpusTotoken_tfidf)

X_data = np.array(corpusTotoken_count)
Y_data = np.array(all_data['labelnum'])
# print(X_data.shape)
# print(Y_data.shape)

---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------

3.2、訓練階段

用線性迴歸和伯努利貝葉斯算法進行預測,並生成預測準確率變化圖

# [4]:訓練階段
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split    # 分割數據集
x_train, x_test, y_train, y_test = train_test_split(X_data, Y_data, test_size = 0.3)

## LR 預測
from sklearn.linear_model.logistic import  LogisticRegression
LR = LogisticRegression()
LR.fit(x_train,y_train) 
predictions_LR = LR.predict(x_test)
prob_LR=LR.predict_proba(x_test)

## Bernoulli bayes 預測
from sklearn.naive_bayes import BernoulliNB
GB = BernoulliNB()
GB.fit(x_train,y_train)
predictions_GB = GB.predict(x_test)
prob_GB=GB.predict_proba(x_test)

# 準確率變化圖
from sklearn.metrics import roc_curve, auc
fpr_LR, tpr_LR, thresholds = roc_curve(y_test, prob_LR[:, 1])
roc_auc_LR = auc(fpr_LR, tpr_LR)
print("roc_auc_LR=", roc_auc_LR)
fpr_GB, tpr_GB, thresholds = roc_curve(y_test, prob_GB[:, 1])
roc_auc_GB = auc(fpr_GB, tpr_GB)
print("roc_auc_GB=", roc_auc_GB)

plt.figure(figsize=(8,6))
plt.title('Receiver Operating Characteristic')
plt.plot(fpr_LR, tpr_LR, 'b',  label='LR_AUC = %0.2f'% roc_auc_LR)
plt.plot(fpr_GB, tpr_GB, 'y',  label='GB_AUC = %0.2f'% roc_auc_GB)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlim([-0.1,1.2])
plt.ylim([-0.1,1.2])
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
plt.show()

迴歸預測與伯努利貝葉斯預測生成的準確圖如下:
在這裏插入圖片描述

---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------

3.3、測試階段

輸入一句新的樣本數據sent ,啓用模型,生成預測的分類結果

# [5]:測試階段
sent = '房間較爲簡單,非常乾淨.'
sent_cut=jieba.lcut(sent)
sent_cut_input=' '.join(sent_cut)
print("切詞結果:", sent_cut_input)

Xpredict=vectorizer.transform([sent_cut_input]).todense()
print("預測的準確率=", GB.predict_proba(Xpredict))
print("預測的標籤=", GB.predict(Xpredict))

得到的預測結果如下,可以通過預測的準確率發現,房間較爲簡單,非常乾淨百分之99%是一條好評;
在這裏插入圖片描述
---------------------------------------------------------------------------------------------------------------------
本篇博客所用到的代碼以及《譚鬆波酒店評論語料》都在這裏可以下載
---------------------------------------------------------------------------------------------------------------------

如有建議,歡迎留言

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章