【机器学习】10:朴素贝叶斯做文本分类

前言:

在文本分类中,垃圾邮件分类是个二分类任务,比较容易说明文本分类的原理,所以以下以垃圾邮件分类为例,讲述使用朴素贝叶斯算法做评论分类的使用方法及过程,后面有本篇代码链接。
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
这里是【机器学习】9:朴素贝叶斯算法原理,对贝叶斯原理不清楚的伙伴,可以自主学习。
---------------------------------------------------------------------------------------------------------------------
本篇博客所用到的代码以及《谭松波酒店评论语料》都在这里可以下载
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------

一、朴素贝叶斯如何应用于垃圾邮件分类

1.1、数据准备阶段:

  1. 在邮件识别中,我们已知有一个训练样本空间集 C = ( X 1 , X 2 , . . . , X n ) C=(X_1,X_2,...,X_n) C=(X1,X2,...,Xn),每条样本数据具有多条属性 X i = ( x i 1 , x i 2 , . . . , x i m ) X_i=(x_{i1},x_{i2},...,x_{im}) Xi=(xi1,xi2,...,xim)
  2. 样本空间所有类别标签: Y = ( y 1 , y 2 , . . . , y m ) Y=(y_1,y_2,...,y_m) Y=(y1,y2,...,ym);样本空间每一条样本 X X X都有一个类别标签 y y y对应;
  3. 用结巴分词将每条样本 X X X切成分词的形式: X = ( x 1 , x 2 , . . . , x k ) X=(x_1,x_2,...,x_k) X=(x1,x2,...,xk)

比如我们已知的两条样本如下:<样本,标签>的形式:

  • X 1 X_1 X1:需要|为|企业|开具|发票,请|联系|我。 ——垃圾邮件
  • X 2 X_2 X2:附件|是|我|做的|报表,如果|可行|,请|批示。 ——非垃圾邮件

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

1.2、数据处理阶段:词袋模型

词袋模型就是将样本空间所有的样本先切词、再去重后得到的词语大集合,配合one-hot编码格式产生如下的词语模型:
在这里插入图片描述

  • 青色: X 1 , X 2 , . . . X_1,X_2,... X1,X2,...每一条都是一个样本数据;
  • 蓝色:就是我们将样本集 C C C中所有的样本用结巴分词切词并去重得到的大词袋,词袋 X a l l = ( x 1 , x 2 , . . , x k , . . , x n ) X_{all}=(x_1,x_2,..,x_k,..,x_n) Xall=(x1,x2,..,xk,..,xn)
  • 橙色:每行的0-1数据就是该样本 X X Xone-hot编码;

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

1.3、贝叶斯计算概率——训练阶段:

依照训练样本集 C = ( X 1 , X 2 , . . . , X n ) C=(X_1,X_2,...,X_n) C=(X1,X2,...,Xn)中的数据:

计算1:垃圾邮件的占比、非垃圾邮件的占比:

  • P ( C = y i ) P(C=y_i) P(C=yi) y i ∈ y_i \in yi ( 是 , 不 是 ) (是,不是) ()

计算2:词袋中每个词,在“是/非”垃圾邮件中出现的概率:

  • P ( x 1 ∣ y i ) P(x_1|y_i) P(x1yi) P ( x 2 ∣ y i ) P(x_2|y_i) P(x2yi),…, P ( x k ∣ y i ) P(x_k|y_i) P(xkyi),…, P ( x n ∣ y i ) P(x_n|y_i) P(xnyi) y i ∈ y_i \in yi ( 是 , 不 是 ) (是,不是) ()

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

1.4、贝叶斯计算概率——测试阶段:

有一测试数据 K K K转化为该词袋模型的one-hot编码为: K = ( x 1 , x 2 , . . . , x l ) K=(x_1,x_2,...,x_l) K=(x1,x2,...,xl),计算 m a x ( P ( x 1 , x 2 , . . . , x l ∣ 是 ) , P ( x 1 , x 2 , . . . , x l ∣ 不 是 ) ) max(P(x_1,x_2,...,x_l|是),P(x_1,x_2,...,x_l|不是)) max(P(x1,x2,...,xl)P(x1,x2,...,xl)),哪个标签的概率大就归入哪个类。

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

扫描二维码关注公众号,回复: 12721856 查看本文章

二、举例:朴素贝叶斯做垃圾邮件分类

2.1、数据准备,数据处理阶段

在这里插入图片描述
有一数据集如上,样本集 C C C一共切出14个词,组成的词袋如下:

  • X a l l = X_{all}= Xall=[‘下午’, ‘酒吧’, ‘开会’, ‘开发票’, ‘有偿’, ‘回复’, ‘4’, ‘信息’, ‘请’, ‘基本’, ‘填写’, ‘收到’, ‘夜店’, ‘点’]

转化得到的one-hot编码矩阵如下:(标签——1:是垃圾邮件; 0:不是垃圾邮件)
在这里插入图片描述
---------------------------------------------------------------------------------------------------------------------

2.2、贝叶斯计算概率——训练阶段:

计算1:垃圾邮件的占比、非垃圾邮件的占比:(已做拉普拉斯平滑)

  • P ( C = 是 ) = P(C=是)= P(C=)= 2 + 1 5 + 2 2+1 \over 5+2 5+22+1 P ( C = 不 是 ) = P(C=不是)= P(C=)= 3 + 1 5 + 2 3+1 \over 5+2 5+23+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,这说明:同一个词语在“是/非”两个标签阵营下并不是完全对立的事件,换句话说 1 − 1- 1 P ( x k ∣ 不 是 ) P(x_k|不是) P(xk)不一定等于 P ( x k ∣ 是 ) P(x_k|是) P(xk)。——这在下面样本测试阶段的时候就能知道它的重要性了。

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

2.3、贝叶斯计算概率——测试阶段:

测试: X n o w = X_{now}= Xnow=“请填写开发票信息”–>“请|填写|开发票|信息”–>[0,0,0,1,0,0,0,1,1,0,1,0,0,0]

X n o w X_{now} Xnow是垃圾邮件的前提下,新样本出现的概率:

  • P ( X n o w ∣ 是 ) = P(X_{now}|是)= P(Xnow)= P ( [ x 1 , x 2 , . . . , x 14 ] ∣ 1 ) = P([x_1,x_2,...,x_{14}]|1)= P([x1,x2,...,x14]1)= ( 1 − P ( x 1 ∣ 1 ) ) ∗ ( 1 − P ( x 2 ∣ 1 ) ) ∗ ( 1 − P ( x 3 ∣ 1 ) ) ∗ P ( x 4 ∣ 1 ) ∗ . . . (1-P(x_1|1))*(1-P(x_2|1))*(1-P(x_3|1))*P(x_4|1)*... (1P(x11))(1P(x21))(1P(x31))P(x41)...

X n o w X_{now} Xnow不是垃圾邮件前提下,新样本出现的概率:

  • P ( X n o w ∣ 不 是 ) = P(X_{now}|不是)= P(Xnow)= P ( [ x 1 , x 2 , . . . , x 14 ] ∣ 0 ) = P([x_1,x_2,...,x_{14}]|0)= P([x1,x2,...,x14]0)= ( 1 − P ( x 1 ∣ 0 ) ) ∗ ( 1 − P ( x 2 ∣ 0 ) ) ∗ ( 1 − P ( x 3 ∣ 0 ) ) ∗ P ( x 4 ∣ 0 ) ∗ . . . (1-P(x_1|0))*(1-P(x_2|0))*(1-P(x_3|0))*P(x_4|0)*... (1P(x10))(1P(x20))(1P(x30))P(x40)...

最后哪个概率大,就把新样本分属到该类中。

说明:

  1. 如果 x i x_i xi在测试语句中出现了,就用其本身的条件概率,比如 x 4 , x 8 , x 9 , x 11 x_4,x_8,x_9,x_{11} x4,x8,x9,x11, 如果 x i x_i xi在测试语句中没有出现,就用(1-本身的条件概率)——(1-本身的条件概率)才是对立事件,因为 ( 1 − P ( x 1 ∣ 1 ) ) (1-P(x_1|1)) (1P(x11))不一定等于 P ( x 1 ∣ 0 ) P(x_1|0) P(x10),所以 P ( X n o w ∣ 是 ) = P(X_{now}|是)= P(Xnow)= P ( [ x 1 , x 2 , . . . , x 14 ] ∣ 1 ) = P([x_1,x_2,...,x_{14}]|1)= P([x1,x2,...,x14]1)= P ( x 1 ∣ 0 ) ∗ P ( x 2 ∣ 0 ) ∗ − P ( x 3 ∣ 0 ) ∗ P ( x 4 ∣ 1 ) ∗ . . . P(x_1|0)*P(x_2|0)*-P(x_3|0)*P(x_4|1)*... P(x10)P(x20)P(x30)P(x41)...,这种计算方式是错误的,请务必知悉;
  2. 一般在计算过程中,为防止数值下逸,会在计算每个 x i x_i xi的概率后做 l o g ( ) log() log()处理。也就是说上式最终形态应该是: P ( X n o w ∣ 是 ) = P(X_{now}|是)= P(Xnow)= P ( [ x 1 , x 2 , . . . , x 14 ] ∣ 1 ) = P([x_1,x_2,...,x_{14}]|1)= P([x1,x2,...,x14]1)= l o g ( 1 − P ( x 1 ∣ 1 ) ) ∗ l o g ( 1 − P ( x 2 ∣ 1 ) ) ∗ l o g ( 1 − P ( x 3 ∣ 1 ) ) ∗ l o g ( P ( x 4 ∣ 1 ) ) ∗ . . . log(1-P(x_1|1))*log(1-P(x_2|1))*log(1-P(x_3|1))*log(P(x_4|1))*... log(1P(x11))log(1P(x21))log(1P(x31))log(P(x41))...

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

三、朴素贝叶斯做文本分类

---------------------------------------------------------------------------------------------------------------------
本篇博客所用到的代码以及《谭松波酒店评论语料》都在这里可以下载
---------------------------------------------------------------------------------------------------------------------
从《谭松波酒店评论语料》截取的部分好评、差评数据如下:
在这里插入图片描述在这里插入图片描述

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

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%是一条好评;
在这里插入图片描述
---------------------------------------------------------------------------------------------------------------------
本篇博客所用到的代码以及《谭松波酒店评论语料》都在这里可以下载
---------------------------------------------------------------------------------------------------------------------

如有建议,欢迎留言

猜你喜欢

转载自blog.csdn.net/zzZ_CMing/article/details/89478436
今日推荐