朴素贝叶斯--(2)

4.文档分类

独立(independence)指的是统计意义上的独立,即一个特征或者单词出现的可能性与它和其他单词相邻没有关系。举个例子讲,设单词bacon出现在unhealthy后面和出现在delicious后面的概率相同。当然,我们知道这种假设并不正确,bacon常常出现在delicious附近,而很少出现在unhealthy附近,这个假设正是朴素贝叶斯分器中朴素(naive)一词的含义。
从词向量计算概率:
w:一个向量,数值个数和词的个数相同。
在这里插入图片描述
在这里插入图片描述
对每个类计算该值,然后比较概率的大小。
(1)通过类别i (侮辱性留言或非侮辱留言)中文档数除以总的文档数来计算概率
(2)计算p(wci)p(w|c_i),这里要用到朴素贝叶斯假设,如果将w展开为一个个独立特征,那么就可以将上述概率写作p(w0,w1,...,wNci)p(w_0,w_1,...,w_N|c_i)。这里假设所有相互独立,该 设也称条件独立性假设,它意味着可以使用p(w0ci)p(w1ci)...p(wNci)p(w_0|c_i)p(w_1|c_i)...p(w_N|c_i)来计算上述概率,这就极大地简化了计算的过程。
在这里插入图片描述
单调性不变。
(3)p(w)p(w)都是相同的,只需要比较分子的大小。

5.垃圾邮件分类

目的:假设我们有一个邮件的文本,我们希望能够判断它是垃圾邮件还是非垃圾邮件。

样本:我们有一批(m个)已经标识为垃圾邮件(y=1)和非垃圾邮件(y=0)的邮件文本。还有相应的字典,字典是有序排列的,包括所有单词。

步骤:
(1)构建空特征向量,xT={0,0,...,0}x^T=\{0,0,...,0\},向量长度为字典长度;
(2)根据邮件中各单词所在的字典位置,将相应位置的赋值为1;如下所示

在这里插入图片描述
这个矩阵的表示这封邮件中有单词a和buy,但不包含单词aardvark、aardwolf和zygmurgy。

(3)由于样本为已经分好类的邮件,因此可得:
在这里插入图片描述

由步骤1到步骤2使用的就是朴素贝叶斯假设。

(4)令Φiy=1=p(xi=1y=1)\Phi_{i|y=1}=p(x_i=1|y=1),它表示的是在该邮件被标为垃圾邮件的前提下,位置i下的单词出现的概率;Φiy=0=p(xi=1y=0)\Phi_{i|y=0}=p(x_i=1|y=0),表示在该邮件被标为非垃圾邮件的前提下,位置i下的单词出现的概率。Φy=p(y=1)\Phi_y=p(y=1),表示一个邮件被标记为垃圾邮件的概率。

训练样本的联合概率为:
在这里插入图片描述
求此最大似然方程,可得参数:
在这里插入图片描述

其中,符号“”表示逻辑“与”,符号“#”表示符合集合中给定条件的样本个数。

e) 假设一个新的样本,其特征值为x,那么就可以计算它为垃圾邮件的概率:

在这里插入图片描述

而它不是垃圾邮件的概率就为1p(y=1x)1-p(y=1|x),比较这两个概率值大小,就可以确定该邮件是否为垃圾邮件。

6.文本特征向量化

朴素贝叶斯模型去给文本数据分类,就必须对文本数据进行处理。

处理的流程一般是:

  • 对文本分词(作为特征)
  • 统计各词在句子中是否出现(词集模型)
  • 统计各词在句子中出现次数(词袋模型)
  • 统计各词在这个文档的TFIDF值(词袋模型+IDF值)

文本特征向量化方法有:
(1)词集模型:one-hot编码向量化文本;
(2)词袋模型+IDF:TFIDF向量化文本;
(3)哈希向量化文本。
(4)word2vec,深度学习模型生成的词向量

6.1.one-hot

表示法先将文本数据集中不重复的单词提取出来,得到一个大小为V的词汇表。然后用一个V维的向量来表示一个文章,向量中的第d个维度上的1表示词汇表中的第d个单词出现在这篇文章中。

如果文本数据集太大,那么得到的词汇表中可能存在几千个单词,这样会文本的维度太大,不仅会导致计算时间增加,而且带来了稀疏问题(one-hot矩阵中大多数元素都是0)。因此,我们通常在计算词汇表的时候,会排除那些出现次数太少的单词,从而降低文本维度。

6.2.tf-idf (term frequency-inverse document frequency)

不仅考虑了单词在文章中的出现次数,还考虑了其在整个文本数据集中的出现次数。TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力。

6.3.Tfidf Vectorizer

在执行时,需要先将词袋矩阵放入内存,再计算各位置单词的TFIDF值,如果词袋维度大,将占用过多内存,效率低,此时可以使用哈希向量化。哈希向量化可以缓解TfidfVectorizer在处理高维文本时内存消耗过大的问题。

6.4.word2vec

不做介绍。

7.代码

7.1.理论实现

(1)计算词汇表
(2)每个样本用(词汇表的词个数,1)表示,即该样本出现该词,值为1,不出现为0
(3)计算:p1Vect - 侮辱类的单词出现概率(vocal,1)
p0Vect - 非侮辱类的单词出现概率(vocal,1)
pAbusive - 文档属于侮辱类的概率int,即p(ci)p(c_i)
p1Vect,p0Vect :根据公式p(w0ci)p(w1ci)...p(wNci)p(w_0|c_i)p(w_1|c_i)...p(w_N|c_i)计算的,计算每个因子。
(4)预测,计算每个样本的表示,把出现词wiw_ip(wici)p(w_i|c_i)相加,得到该分类cic_i的可能性,对cic_i进行比较,选取最大的作为标签。

import numpy as np

def loadDataSet():
    """
    创建实验样本
    :return:
    postingList - 实验样本切分的词条
    classVec - 类别标签向量
    """
    # 切分的词条
    postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                 ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                 ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                 ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                 ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                 ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]

    classVec = [0,1,0,1,0,1]  # 类别标签向量,1代表侮辱性词汇,0代表不是
    return postingList,classVec
                 

def setOfWords2Vec(vocabList, inputSet):
    """
    根据vocabList词汇表,将inputSet向量化,向量的每个元素为1或0
    :param vocabList: createVocabList返回的列表
    :param inputSet: 切分的词条列表
    :return: 文档向量,词袋模型[0,1,0,0,...]
    """
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else: print ("词 %s 不在词汇表中" % word)
    return returnVec

def trainNB0(trainMatrix,trainCategory):
    """
    朴素贝叶斯分类器训练函数
    :param trainMatrix:文档矩阵,(samples,vocabulary)[[0,0,1,...],[]]
    :param trainCategory:训练类标签向量,[0,0,1],1表示侮辱类
    :return:
    p1Vect - 侮辱类的单词出现概率(vocal,1)
    p0Vect - 非侮辱类的单词出现概率(vocal,1)
    pAbusive - 文档属于侮辱类的概率int
    """
    numTrainDocs = len(trainMatrix)  # 训练样本的个数
    numWords = len(trainMatrix[0])  # 词汇个数
    pAbusive = sum(trainCategory)/float(numTrainDocs)  # 文档属于侮辱类的概率
    p0Num = np.ones(numWords)  # (1,vocal)
    p1Num = np.ones(numWords)  # (1,vocal)
    # 分母初始化为2,拉普拉斯平滑
    p0Denom = 2.0  # 类别0的所有样本的每个单词的出现的总数
    p1Denom = 2.0
    for i in range(numTrainDocs):  # 每个样本
        if trainCategory[i] == 1:  # 类别1
            p1Num += trainMatrix[i]  # 每个单词的个数,[0,0,1,...]+[0,1,1,...]
            p1Denom += sum(trainMatrix[i])
        else:  # 类别0
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect = np.log(p1Num/p1Denom)  # 类别1中一个单词出现的次数/类别1中所有单词出现的个数
    p0Vect = np.log(p0Num/p0Denom)
    return p0Vect,p1Vect,pAbusive

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    """

    :param vec2Classify:(vocal,1)[0,1,0,1]
    :param p0Vec:非侮辱类的单词出现概率(vocal,1)
    :param p1Vec:侮辱类的单词出现概率(vocal,1)
    :param pClass1:文档属于侮辱类的概率int
    :return:int
    """
    # 如果出现该词,则将该词的概率加上
    p1 = sum(vec2Classify * p1Vec) + np.log(pClass1)    # element-wise mult
    p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else: 
        return 0


def createVocabList(dataSet):
    """
    将切分的实验样本词条整理成不重复的词条列表,也就是词汇表
    :param dataSet:整理的样本数据集
    :return:返回不重复的词条列表,也就是词汇表
    """
    vocabSet = set([])  #create empty set
    for document in dataSet:
        vocabSet = vocabSet | set(document)  # 两个set的union
    return list(vocabSet)

def estingNB():
    """

    :return:
    """
    listOPosts,listClasses = loadDataSet()  # 数据,类别

    myVocabList = createVocabList(listOPosts)  # 创建词汇表
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    # (vocal,1),(vocal,1),int
    p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))
    testEntry = ['love', 'my', 'dalmation']
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
    testEntry = ['stupid', 'garbage']
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))


if __name__ == '__main__':
    estingNB()

7.2.sklearn

7.3.贝叶斯的种类

sklearn有

7.3.1.高斯朴素贝叶斯

GaussianNB 实现高斯朴素贝叶斯算法进行分类。 特征的可能性被假设为高斯函数的形式:
在这里插入图片描述
参数 σyσ_yμyμ_y 使用最大似然法估计

API: https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.GaussianNB.html#sklearn.naive_bayes.GaussianNB

7.3.2.多项分布的朴素贝叶斯

MultinomialNB 实现了服从多项分布数据的朴素贝叶斯算法,也是用于文本分类(这个领域中数据往往以词向量表示,尽管在实践中 tf-idf 向量在预测时表现良好)的两大经典朴素贝叶斯算法之一。 分布参数由每类 y 的 θy = (θy1,…,θyn) 向量决定, 式中 n 是特征的数量(对于文本分类,是词汇量的大小),θyi 是样本中属于类 y 中特征 i 概率 P(xi | y) 。

参数 θy 使用平滑过的最大似然估计法来估计,即相对频率计数:
在这里插入图片描述
在这里插入图片描述

是训练集T类 y中出现所有特征的计数总和。先验平滑因子 α>=0, 应用于在学习样本中没有出现的特征,以防在将来的计算中出现0概率输出。 把 α = 1 称为拉普拉斯平滑(Lapalce smoothing),而 α <1被称为利德斯通平滑(Lidstone smoothing)。

API: https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.ComplementNB.html#sklearn.naive_bayes.ComplementNB

7.3.3.伯努利朴素贝叶斯

BernoulliNB 实现了用于多重伯努利分布数据的朴素贝叶斯训练和分类算法,即有多个特征,但每个特征 都假设是一个二元 (Bernoulli, boolean) 变量。 因此,这类算法要求样本以二元值特征向量表示;如果样本含有其他类型的数据, 一个 BernoulliNB 实例会将其二值化(取决于 binarize 参数)。伯努利朴素贝叶斯的决策规则基于
在这里插入图片描述
与多项分布朴素贝叶斯的规则不同 伯努利朴素贝叶斯明确地惩罚类 y 中没有出现作为预测因子的特征 i ,而多项分布分布朴素贝叶斯只是简单地忽略没出现的特征。

在文本分类的例子中,词频向量(而非词数向量)可能用于训练和用于这个分类器。 BernoulliNB 可能在一些数据集上可能表现得更好,特别是那些更短的文档。

API: https://scikit-learn.org/stable/modules/generated/sklearn.naive_bayes.BernoulliNB.html#sklearn.naive_bayes.BernoulliNB

7.3.4.堆外朴素贝叶斯模型拟合

朴素贝叶斯模型可以解决整个训练集不能导入内存的大规模分类问题。 为了解决这个问题, MultinomialNB, BernoulliNB, 和 GaussianNB 实现了 partial_fit 方法,可以动态的增加数据,使用方法与其他分类器的一样,所有的朴素贝叶斯分类器都支持样本权重。

注:与 fit 方法不同,首次调用 partial_fit 方法需要传递一个所有期望的类标签的列表。所有朴素贝叶斯模型调用 partial_fit 都会引入一些计算开销。推荐让数据快越大越好,其大小与 RAM 中可用内存大小相同。

7.3.5.iris数据

# coding: utf-8
# Author: shelley
# 2020/6/39:22
from sklearn import datasets

iris = datasets.load_iris()

from sklearn.naive_bayes import GaussianNB
# 高斯朴素贝叶斯
clf = GaussianNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("高斯朴素贝叶斯,样本总数: %d 错误样本数 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
from sklearn.naive_bayes import MultinomialNB
# 多项分布的朴素贝叶斯
clf = MultinomialNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("多项分布朴素贝叶斯,样本总数: %d 错误样本数 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
from sklearn.naive_bayes import BernoulliNB
# 伯努利朴素贝叶斯
clf = BernoulliNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("伯努利朴素贝叶斯,样本总数: %d 错误样本数 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
# 高斯朴素贝叶斯,样本总数: 150 错误样本数 : 6
# 多项分布朴素贝叶斯,样本总数: 150 错误样本数 : 7
# 伯努利朴素贝叶斯,样本总数: 150 错误样本数 : 100

7.3.6.文本

# coding=utf-8

from sklearn.datasets import fetch_20newsgroups
# 从sklearn.datasets里导入新闻数据抓取器 fetch_20newsgroups
from sklearn.model_selection import  train_test_split
from sklearn.feature_extraction.text import CountVectorizer
# 从sklearn.feature_extraction.text里导入文本特征向量化模块
from sklearn.naive_bayes import MultinomialNB
# 从sklean.naive_bayes里导入朴素贝叶斯模型
from sklearn.metrics import classification_report

# 1.数据获取
news = fetch_20newsgroups(subset='all')
print(len(news.data))  # 输出数据的条数:18846

# 2.数据预处理:训练集和测试集分割,文本特征向量化
X_train,X_test,y_train,y_test = train_test_split(news.data,news.target,test_size=0.25,random_state=33)
# 随机采样25%的数据样本作为测试集
# print X_train[0]  # 查看训练样本
# print y_train[0:100]  # 查看标签

# 文本特征向量化
vec = CountVectorizer()
X_train = vec.fit_transform(X_train)
X_test = vec.transform(X_test)

# 3.使用朴素贝叶斯进行训练
mnb = MultinomialNB()   # 使用默认配置初始化朴素贝叶斯
mnb.fit(X_train,y_train)    # 利用训练数据对模型参数进行估计
y_predict = mnb.predict(X_test)     # 对参数进行预测

# 4.获取结果报告
print('The Accuracy of Naive Bayes Classifier is:', mnb.score(X_test,y_test))
print(classification_report(y_test, y_predict, target_names = news.target_names))
# 18846
# The Accuracy of Naive Bayes Classifier is: 0.839770797963
#                           precision    recall  f1-score   support
#
#              alt.atheism       0.86      0.86      0.86       201
#            comp.graphics       0.59      0.86      0.70       250
#  comp.os.ms-windows.misc       0.89      0.10      0.17       248
# comp.sys.ibm.pc.hardware       0.60      0.88      0.72       240
#    comp.sys.mac.hardware       0.93      0.78      0.85       242
#           comp.windows.x       0.82      0.84      0.83       263
#             misc.forsale       0.91      0.70      0.79       257
#                rec.autos       0.89      0.89      0.89       238
#          rec.motorcycles       0.98      0.92      0.95       276
#       rec.sport.baseball       0.98      0.91      0.95       251
#         rec.sport.hockey       0.93      0.99      0.96       233
#                sci.crypt       0.86      0.98      0.91       238
#          sci.electronics       0.85      0.88      0.86       249
#                  sci.med       0.92      0.94      0.93       245
#                sci.space       0.89      0.96      0.92       221
#   soc.religion.christian       0.78      0.96      0.86       232
#       talk.politics.guns       0.88      0.96      0.92       251
#    talk.politics.mideast       0.90      0.98      0.94       231
#       talk.politics.misc       0.79      0.89      0.84       188
#       talk.religion.misc       0.93      0.44      0.60       158
#
#                 accuracy                           0.84      4712
#                macro avg       0.86      0.84      0.82      4712
#             weighted avg       0.86      0.84      0.82      4712

8.代码和数据

链接:https://pan.baidu.com/s/1QbeG8g_9JhVwJRhERViTMg
提取码:80su
github:
https://github.com/shelleyHLX/machine-learning

9.reference

吴军的google黑板报数学之美专题
Andrew Ng的机器课程
https://blog.csdn.net/linkin1005/article/details/39025879

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