机器学习之朴素贝叶斯

1. 必须理解的基础理论

  在认识朴素贝叶斯以前,必须查阅资料理解条件几率和贝叶斯法则,这是掌握朴素贝叶斯分类方法的理论基础算法

(1)条件几率app

  p(x=a|y=b) 表示在y=b成立的条件下x=a的几率less

  p(x=a|y=b) = p(x=a,y=b) / p(x = a)机器学习

(2)贝叶斯法则函数

  朴素贝叶斯最核心的部分是贝叶斯法则,贝叶斯法则的基石是条件几率,贝叶斯法则告诉咱们如何交换条件几率中的条件和结果,即若是已知p(x,y|c)计算p(c|x,y) post

     

2. 什么是朴素贝叶斯

(1)概述学习

  朴素贝叶斯是为数很少的基于几率论的分类算法,经过考虑特征几率来预测分类,多用于文本分类,下面举个粗略的例子:测试

  邮件的分类为[垃圾邮件,非垃圾邮件]ui

  如今有封邮件,里面就三词[广告,会议,新闻]spa

  前提:根据训练数据知道p(广告|垃圾),p(会议|垃圾),p(新闻|垃圾)和p(广告|非垃圾),p(会议|非垃圾),p(新闻|非垃圾)

  计算出在垃圾邮件中特征词共同出现的几率 p1 = p(广告)*p(会议)*p(新闻)

  计算出在非垃圾邮件中特征词共同出现的几率 p2 = p(广告)*p(会议)*p(新闻)

  若p1 > p2则推测该邮件为垃圾邮件,反之,推测为非垃圾邮件,若是有邮件的分类还有第三类,就继续算出p3,而后计算max(p1,p2,p3)

  上面就是贝叶斯决策理论的核心思想,即选择具备最高几率的决策

(2)为什么称为朴素

  咱们称之为“朴素”,是由于整个形式化过程当中只作最原始、最简单的假设,假设每一个词都是独立的特征,假设全部词相互条件独立,一个词的出现并不依赖于文档中的其余词。

3. 使用朴素贝叶斯对文档分类

  以在线社区的留言板为例,为了避免影响社区的发展,咱们要屏蔽侮辱性的言论,因此要创建一个快速的过滤器,若是某条留言使用了负面或者侮辱性的语言,那么就将该留言表示为内容不当。

  需求:根据留言板内容,设计贝叶斯过滤器负责检测留言内容是否属于侮辱性言论

(1)朴素贝叶斯的通常过程

  a. 准备数据:训练文档

  b. 分析数据:有大量特征时,绘制特征做用不大,此时使用直方图效果好

  c. 训练数据:计算不一样的独立特征的条件几率

  d. 测试算法:计算错误率

  e. 使用算法

(2)准备数据

  准备6条留言板内容,及其确认的类别(侮辱性言论和正常言论),下面代码中postingList为留言板列表,classVec 为每条留言对应的类别

def loadDataSet():
    """
    建立数据集
    """
    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 is abusive, 0 not
    return postingList, classVec

(3)建立特征词汇数据集,遍历全部留言,将特征词添加到词聚集中

def create_vocab_list(dataset):
    """
    根据数据集建立词汇列表
    """
    vocabset = set([])
    for doc in dataset:
        vocabset = vocabset | set(doc)
    return list(vocabset)

(3)根据特征词集分别将每条留言转换为向量,该向量能够是词集也能够是词袋

  词集模式:对于给定文档,只统计某个词是否出如今本文档中,而不统计出现的次数

  词袋模式:对于给定的文档,统计某个词在本文档中出现的次数,除此以外,每每还须要剔除重要性极低的高频词和停用词

  下面代码是基于词袋的:

def trans_doc_to_vector(vocablist, inputset):
    """
    将输入词汇经过词汇表转换为向量
    例:vocablist = ['hello','world','fate0729']
        inputset = ['a','hello','b','c']
        return [0,1,0,0]
    """
    count = len(vocablist)
    return_vector = [0]*count
    for word in inputset:
        if word in vocablist:
            return_vector[vocablist.index(word)] += 1
    return return_vector    

(4)训练算法

  计算出特征词聚集中的每一个特征值分别在侮辱性言论留言和正常性言论中留言的几率

  以计算每一个特征值在侮辱性言论类别留言中的几率为例进行说明

  a. 统计每一个特征值分别在侮辱性言论留言中出现的总次数num1.....numN

  b. 统计全部特征值在侮辱性言论留言中出现的总次数sum

  c. 计算每一个特征值在侮辱性言论类别留言中的几率 num1/sum ... numN/sum

  注意

  a. 因为在使用贝叶斯算法时会使用到几率相乘的状况,为了不几率值为0的状况,能够将全部词的出现次数初始化为1,sum初始化为2

  b. 因为太多很小的数相乘容易形成程序下溢出或者得不到正确的答案,咱们能够选择对成绩取天然对数

def bayes_train(train_matrix,train_caltegory):
    """
    训练集
    train_matrix:转换后的文档向量
    train_caltegory:文档类型
    """
    docs = len(train_matrix)  #文章数量
    wordnum_in_docs = len(train_matrix[0]) #文章的单词数
    p0num = np.ones(wordnum_in_docs)
    p1num = np.ones(wordnum_in_docs)
    p0Denom = 2
    p1Denom = 2
    for i in range(docs):
        if train_caltegory[i] == 1:
            p1num += train_matrix[i] #单词在类型1的全部文章中出现的次数
            p1Denom += sum(train_matrix[i]) #类型1的文章中在词汇表中出现的总次数
        else:
            p0num += train_matrix[i]
            p0Denom += sum(train_matrix[i])
    
    p1vect = np.log(p1num / p1Denom)  #全部单词在类型1的文章中出现的几率
    p0vect = np.log(p0num / p0Denom)  #全部单词在类型0的文章中出现的几率
    pAb = sum(train_caltegory) / len(train_caltegory)#类型1在全部类型中的几率
    return p0vect,p1vect,pAb

  先测试下,看看特征词聚集和训练算法返回结果:

if __name__ == '__main__':
    postingList, classVec = loadDataSet()
    vocablist = create_vocab_list(postingList)
    print('vocablist:',vocablist)
    return_vectors = []
    for item in postingList:
        return_vector = trans_doc_to_vector(vocablist,item)
        return_vectors.append(return_vector)
    p0vect,p1vect,pAb = bayes_train(return_vectors, classVec)
    print("pAb:",pAb)
    print('p0vect:',p0vect)
    print('p0vect:',p1vect)

  输出:

  vocablist为特征词聚集,pAb为侮辱性留言占总留言的比例,p0vect为特征词在正常性言论留言中的几率,p1vect为特征词在正常性言论留言中的几率

  以stupid为例,stupid在p0vect中的几率为-3.25896,而在p1vect中的几率为-1.65822808,且为p1vect中最大值,这意味着stupid最能表明侮辱性留言类别

(5)朴树贝叶斯分类函数

def classify(pAb,p0vect,p1vect,test_vect):
    """
    分类
    """
    p1 = sum(test_vect*p1vect) + math.log(pAb)
    p0 = sum(test_vect*p0vect) + math.log((1-pAb))
    print("p0:",p0)
    print("p1:",p1)
    if p1 > p0:
        return 1
    else:
        return 0

  该函数比较test_vect向量在类型0类型1中的几率,能够回头看看贝叶斯函数原型

(6)测试

  给条留言进行测试

  test_doc = ['love', 'my', 'dalmation']

  test_doc1 = ['stupid', 'garbage']

test_doc = ['love', 'my', 'dalmation']
test_doc_vect = np.array(trans_doc_to_vector(vocablist, test_doc))
label = classify(pAb,p0vect,p1vect,test_doc_vect)
print("留言类型为:",label)
test_doc1 = ['stupid', 'garbage']
test_doc_vect1 = np.array(trans_doc_to_vector(vocablist, test_doc1))
label1 = classify(pAb,p0vect,p1vect,test_doc_vect1)
print("留言类型为:",label1)
        

  输出:

  即第一条留言为正常性言论,第二条为侮辱性留言

 4. 总结

(1)对于分类而言,使用几率有时比使用硬规则更为有效,贝叶斯提供了一种利用已知值来估计未知几率的有效方法

(2)特征之间的条件独立性假设,显然这种假设显得“粗鲁”而不符合实际,这也是名称中“朴素”的由来。然而事实证实,朴素贝叶斯在有些领域颇有用,好比垃圾邮件过滤;

(3)在具体的算法实施中,要考虑不少实际问题,好比由于“下溢”问题,须要对几率乘积取对数,再好比词集模型和词袋模型,还有停用词和无心义的高频词的剔除,以及大量的数据预处理问题,等等

(4)此分类器的准确率很是依赖于训练集,机器学习算法就和纯洁的小孩同样,取决于其成长(训练)条件,“吃的是草挤的是奶”,但,“不是全部的牛奶,都叫特仑苏”

相关文章
相关标签/搜索