机器学习实战 朴素贝叶斯

来源:互联网 发布:mac驱动下载 编辑:程序博客网 时间:2024/05/18 03:03

– 朴素贝叶斯的思想是对样本属于每一个类别的情况求概率,认为概率最高的类别就是这个样本的类别。所以它可以用来解决多类别的问题,同时也只能对标称型的数据处理。
– 在理解它是怎么分类之前,需要掌握条件概率的理论。如果把这种分类方法与条件概率结合起来理解的话,就是P(类别|样本)=P(样本|类别)*P(类别)/P(样本)。和我们的理解一样,如果要判断这个样本的类别,就去判断已知这个样本属于某个类别的概率,然后比较选择最高的概率。

  • 接下来以书上的文档分类为例,具体阐述朴素贝叶斯的用法。我们希望判断在线社区留言板中的留言是否属于侮辱性的。
    步骤如下:
      1. 从文本中构造词向量,目的是后面可以用词向量来计算概率。
      • 构造的方法是,先读入所有的训练集文本,注意这个文本是按照一个单词作为一个字符串的格式构成的,利用训练集文本的所有字符串构造字典,很显然这个字典就包括了所有文本中出现的所有单词。
      • 再循环输入某个训练集文本,对应着字典中的单词,一个个去寻找,这个单词是否在输入的训练集文本中出现,出现了就标1,没出现就标0.于是得到了和字典向量一样长的词向量。代码分析如下:
def createVocabList(dataSet):#创建文档中所有出现过的词,去重之后的列表    vocabSet = set([])      for document in dataSet:        vocabSet = vocabSet | set(document)     return list(vocabSet)def setOfWords2Vec(vocabList, inputSet):#文档转化为向量形式,输入字典,文档    returnVec = [0]*len(vocabList)    for word in inputSet:        if word in vocabList:#文档中的词在字典中,则字典中这个词的位置标1            returnVec[vocabList.index(word)] = 1            #最终输出的向量,标1的表示文档中有这个词,0的表示文档中无这个词        else: print "the word: %s is not in my Vocabulary!" % word    return returnVec
    1. 训练算法:从词向量计算概率
    • 2.1 根据贝叶斯公式,我们现在要计算的是P(样本|类别)和P(类别),其中P(样本|类别)=P(单词1|类别)*P(单词2|类别)···
      之所以这样是因为,我们现在的样本变成了词向量的形式,朴素贝叶斯称之为朴素的原因是由它有两个假设:其一是条件独立性——一个特征或者单词出现的可能性与它和其他单词相邻没有关系;其二是每个特征同等重要。根据条件独立性,认为每个单词都是条件独立的,那我们就可以把词向量中每个单词单独做乘积。
      2.2 我们得到了上面的公式,如何求概率呢。首先,解决P(类别),这个很好理解,就是去计算训练集中正样本所占的比例和负样本所占的比例,把这个比值作为概率值。
      2.3 然后是P(单词|类别),这个也和上面道理一样,去找训练集中正样本中某个单词所占的比例,负样本同。
      代码分析:
def trainNB0(trainMatrix,trainCategory):#计算后验概率,输入训练样本,标签    numTrainDocs = len(trainMatrix)    numWords = len(trainMatrix[0])    pAbusive = sum(trainCategory)/float(numTrainDocs)    #计算先验概率,也就是计算正类的样本占总样本的比例    p0Num = ones(numWords); p1Num = ones(numWords)      #change to ones()    #设置初始为1,为了避免后续后验概率乘积为0    p0Denom = 2.0; p1Denom = 2.0                        #change to 2.0    for i in range(numTrainDocs):        if trainCategory[i] == 1:            p1Num += trainMatrix[i]            p1Denom += sum(trainMatrix[i])        else:            p0Num += trainMatrix[i]            p0Denom += sum(trainMatrix[i])        #对不同类别的训练样本,算每个词在这个类别中出现的概率    p1Vect = log(p1Num/p1Denom)          #change to log()    p0Vect = log(p0Num/p0Denom)          #change to log()#返回两种类别的后验概率列表和类别为1的先验概率

现在我们得到了两种类别的后验概率和先验概率。开始测试。在测试之前,需要对上面的代码解释一下,之所以把所有单词出现的次数初始化为1,是因为若出现次数为0的情况,那概率值也为0,乘积之后整个就为0了。所以认为的设定了一个初始值。

– 分类的时候,也是将测试样本转化为词向量的形式,去与我们上一步求得的各个单词的概率相乘,得到这个测试样本词向量的概率。对两种类别,分别去求测试样本属于这个类别的概率,比较大小,概率较大的则认为更可能属于这个类别。
代码分析:

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):#测试    p1 = sum(vec2Classify * p1Vec) + log(pClass1)        #每个词后验概率乘积,等于测试样本向量属于类别1的概率,再乘以类别为1的先验概率,根据贝叶斯公式,就是这个向量属于类别1的概率    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)    if p1 > p0:    #分类的准则是,算这个样本属于每一类样本的概率,概率最大的则属于这个类        return 1    else:         return 0  

– 以上的方法在转化为词向量的步骤中,如果这个单词出现就记为1,这种模型称为词集模型。还有一种词袋模型,去计算这个单词出现的总次数。

#词袋模型,列表中每一个元素不再是0 1,也是这个位置的单词出现的次数    def bagOfWords2VecMN(vocabList, inputSet):    returnVec = [0]*len(vocabList)    for word in inputSet:        if word in vocabList:            returnVec[vocabList.index(word)] += 1    return returnVec 

– 书中还介绍了一个垃圾邮件分类的例子,思想是和上面例子的思想是一样的,不同的是利用的词袋模型。并且计算了错误率,计算错误率的时候使用了交叉验证(多次随机选择测试集训练集,计算错误率的平均值)。

0 0
原创粉丝点击