前言:
在文本分類中,垃圾郵件分類是個二分類任務,比較容易說明文本分類的原理,所以以下以垃圾郵件分類爲例,講述使用樸素貝葉斯算法做評論分類的使用方法及過程,後面有本篇代碼鏈接。
–-----------------------------------------------------------------------------—----------------------------------------
–-----------------------------------------------------------------------------—----------------------------------------
這裏是【機器學習】9:樸素貝葉斯算法原理,對貝葉斯原理不清楚的夥伴,可以自主學習。
–-----------------------------------------------------------------------------—----------------------------------------
本篇博客所用到的代碼以及《譚鬆波酒店評論語料》都在這裏可以下載
–-----------------------------------------------------------------------------—----------------------------------------
–-----------------------------------------------------------------------------—----------------------------------------
一、樸素貝葉斯如何應用於垃圾郵件分類
1.1、數據準備階段:
- 在郵件識別中,我們已知有一個訓練樣本空間集,每條樣本數據具有多條屬性;
- 樣本空間所有類別標籤: ;樣本空間每一條樣本都有一個類別標籤對應;
- 用結巴分詞將每條樣本切成分詞的形式:
比如我們已知的兩條樣本如下:<樣本,標籤>的形式:
- :需要|爲|企業|開具|發票,請|聯繫|我。 ——垃圾郵件
- :附件|是|我|做的|報表,如果|可行|,請|批示。 ——非垃圾郵件
–-----------------------------------------------------------------------------—----------------------------------------
1.2、數據處理階段:詞袋模型
詞袋模型就是將樣本空間所有的樣本先切詞、再去重後得到的詞語大集合,配合one-hot
編碼格式產生如下的詞語模型:
- 青色:每一條都是一個樣本數據;
- 藍色:就是我們將樣本集中所有的樣本用結巴分詞切詞並去重得到的大詞袋,詞袋;
- 橙色:每行的0-1數據就是該樣本的
one-hot
編碼;
–-----------------------------------------------------------------------------—----------------------------------------
1.3、貝葉斯計算概率——訓練階段:
依照訓練樣本集中的數據:
計算1:垃圾郵件的佔比、非垃圾郵件的佔比:
- ,
計算2:詞袋中每個詞,在“是/非”垃圾郵件中出現的概率:
- ,,…,,…,,
–-----------------------------------------------------------------------------—----------------------------------------
1.4、貝葉斯計算概率——測試階段:
有一測試數據轉化爲該詞袋模型的one-hot
編碼爲:,計算,哪個標籤的概率大就歸入哪個類。
–-----------------------------------------------------------------------------—----------------------------------------
–-----------------------------------------------------------------------------—----------------------------------------
–-----------------------------------------------------------------------------—----------------------------------------
二、舉例:樸素貝葉斯做垃圾郵件分類
2.1、數據準備,數據處理階段
有一數據集如上,樣本集一共切出14個詞,組成的詞袋如下:
- [‘下午’, ‘酒吧’, ‘開會’, ‘開發票’, ‘有償’, ‘回覆’, ‘4’, ‘信息’, ‘請’, ‘基本’, ‘填寫’, ‘收到’, ‘夜店’, ‘點’]
轉化得到的one-hot
編碼矩陣如下:(標籤——1:是垃圾郵件; 0:不是垃圾郵件)
–-----------------------------------------------------------------------------—----------------------------------------
2.2、貝葉斯計算概率——訓練階段:
計算1:垃圾郵件的佔比、非垃圾郵件的佔比:(已做拉普拉斯平滑)
- ,
計算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,這說明:同一個詞語在“是/非”兩個標籤陣營下並不是完全對立的事件,換句話說不一定等於 。——這在下面樣本測試階段的時候就能知道它的重要性了。
–-----------------------------------------------------------------------------—----------------------------------------
2.3、貝葉斯計算概率——測試階段:
測試:“請填寫開發票信息”–>“請|填寫|開發票|信息”–>[0,0,0,1,0,0,0,1,1,0,1,0,0,0]
在是垃圾郵件的前提下,新樣本出現的概率:
在不是垃圾郵件前提下,新樣本出現的概率:
最後哪個概率大,就把新樣本分屬到該類中。
說明:
- 如果在測試語句中出現了,就用其本身的條件概率,比如, 如果在測試語句中沒有出現,就用(1-本身的條件概率)——(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%是一條好評;
–-----------------------------------------------------------------------------—----------------------------------------
本篇博客所用到的代碼以及《譚鬆波酒店評論語料》都在這裏可以下載
–-----------------------------------------------------------------------------—----------------------------------------