基于概率论进行分类

1.概述

knn算法 决策树都是给出具体某个分类,但有时候并不能确定给出某个分类,而只能给出最优分类及其概率,这种情况可以使用基于概率论的分离算法,比如朴素的贝叶斯算法

截图自《机器学习实战》:



贝叶斯决策理论的核心,选择出现概率最高的分类,选择最高概率的决策。

2,应用

 文档分类,通过观察文档实例中特征词出现或者不出现作为一个判断特征,这样会出现很多判断特征,不适合专家系统的决策树,也不适合大量计算的KNN,可以看出每种算法都有其适用的场景,就像厨房里不同的刀具一样,有专门用来切肉的刀,也有切水果的水果刀。所以, 需要做到两方面:1.熟悉算法原理 2.熟悉应用场景

 要理解朴素贝叶斯决策,需要先理解条件概率及贝叶斯准则,考虑下面一个例子:

 现在有一些石头,3个灰色,4个黑色



问:

      1)、取到灰色石头的概率 ?  很简单,灰色石头个数/总的石头个数=3/7 

      2)  取到黑色石头的概率? 4/7

现在将问题升级,分别放到两个桶里A,B,如下图:



  问:

  1) 从B桶中取灰色石头的概率? p(gray|bucketB)=p(gray,bucketB)/p(bucketB)=1/7/3/7=1/3  =>可以看出,计算方法为,直接锁定B桶(已知条件),然后取灰色球的个数除以B桶中球的总数即可=>如果将A B想象成分类,可以看出,可以计算出特定分类下,某种特征(颜色)出现的条件概率,不过需要假设不同特征之间是相互独立的。计算方法为,统计固定分类下,某个特征值的个数(比如,统计指定分类的文档中单词出现的次数),然后除以“固定分类”下总的特征个数(比如,统计某个分类的文档中所有单词的个数),这样就可以得到这个分类下,某个(或者多个,向量)单词的出现概率

2)反过来问,取到灰色石头落在B桶的概率??很有意思吧,嘿嘿

  根据贝叶斯准则,p(bucketB|gray)=p(gray|bucketB)p(bucketB)/p(gray)=(1/3 * 3/7)/3/7=1/3 =>可以看出,计算方法为,先根据贝叶斯准则建立起跟上面求出的p(gray|bucketB)的联系,可以看出贝叶斯准则表达的是,“可以根据已知的先验经验,然后加推理,可以做出预测”,通俗的举个例子,比如:一个好人很可能会做一些好事,那么通过一些好事他是否做过,可以判断一个人是否为好人,当然这是个概率问题。=>对于文档分类也一样,前面根据样本数据可以计算出,固定分类下,文档中的单词出现的概率,反过来,根据这些经验数据,可以去预测一篇文档落在哪个分类里。


引自《机器学习实战》一段话,也是利用条件概率进行分类算法的理论基础:



 代码实现:

    使用朴素贝叶斯算法实现文档分类,使用文档中的单词是否出现作为特征,这样得到的特征可能会非常多。注意我们假设各个特征是独立的,这样不一定符合实际使用场景,但是可以简化我们的计算,减少样本数据量。在这里就是假设单词之间没有相互关系,彼此出现的概率相同,这也是朴素贝叶斯算法的朴素的意思。第二个假设是,每个特征同等重要。引自《机器学习实战》,朴素贝叶斯的一般过程:

  

 


bayes.py:


 
 
 
from numpy import *
import re
'''
朴素贝叶斯算法实现分类,该算法有时候不是为了准备分类,而是想通过算法发现数据背后相关的内容。学习通过修正从样本中获取的数据,
比如去掉最值,移除辅助词,观察正确率变化,提高算法的精确度。
'''


# 加载数据
def loadDataSet():
    postingList = [['my', 'dog', 'has', 'flea', 'problem', 'help', 'please'],
                   ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                   ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                   ['stop', 'posting', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                   ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                   ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec


# 创建词汇表
# 提取数据集每个元素,去重返回列表
def createCabList(dataset):
    vocabSet = set()

    for item in dataset:
        vocabSet = vocabSet | set(item)

    return list(vocabSet)


# 检查输入的词汇列表是否在词汇表中出现,如果出现就置对应位置为1
# 将输入的一组单词转换成数字向量
#这个是词集模型,每个单词在文档中特征为,是否出现
def setofWords2Vec(vocabList, inputlist):
    resultVec = [0] * len(vocabList)

    for item in inputlist:

        if item in vocabList:
            resultVec[vocabList.index(item)] = 1

    return resultVec

#如果一个单词出现多次,为了记录这个特征的信息,需要词袋模型def bagofWords2VecMN(vocabList, inputlist):
    resultVec = [0] * len(vocabList)

    for item in inputlist:

        if item in vocabList:
            resultVec[vocabList.index(item)] += 1

    return resultVec
# 获取训练矩阵
def getTrainMatrix(vocabList, postingList):
    trainMatirx = []

    for posting in postingList:
        trainMatirx.append(setofWords2Vec(vocabList, posting))

    return trainMatirx


# 计算固定分类下的条件概率
# 输入:特征值矩阵 分类向量
def trainNB0(trainMatrix, classVec):
    # 文档个数
    numTrainDocs = len(trainMatrix)
    # 特征维度-单词个数
    numWords = len(trainMatrix[0])
    # 计算侮辱性分类的文档出现的概率p(c1)
    pAbusive = (sum(classVec)) / float(len(classVec))
    # 初始化单词在不同分类下的概率向量和出现总数
    # 注意这里需要进行矩阵运算,不能直接使用list,需要使用numpy中的array进行计算
    # p0num=[0]*numWords
    # p0num=zeros(numWords)
    # 防止多个特征值概率相乘,其中一个为0,导致整体为0
    p0num = ones(numWords)
    # p1num=[0]*numWords
    # p1num=zeros(numWords)
    p1num = ones(numWords)
    # p0totalnum=0.0
    p0totalnum = 2.0
    # p1totalnum=0.0
    p1totalnum = 2.0
    # 遍历特征值矩阵,按照分类向量中指定文档类型,进行分类,然后计算条件概率p(w|ci)
    for i in range(numTrainDocs):
        # 如果i行是侮辱性文档
        if classVec[i] == 1:
            # 进行单词出现个数的向量累积,想象下那个灰色或者黑色的球吧,嘿嘿
            p1num += trainMatrix[i]
            # 统计这个分类下的单词总数,想象下那个B桶中的所有球
            p1totalnum += sum(trainMatrix[i])
        # 如果是非侮辱性文档
        else:
            p0num += trainMatrix[i]
            p0totalnum += sum(trainMatrix[i])

    # 计算条件概率,p(w|ci) w是单词出现次数的向量矩阵

    # p0Vect=p0num/p0totalnum
    # p1Vect=p1num/p1totalnum
    # 防止很多小的数相乘导致下溢出ln(ab)=lna+lnb
    p0Vect = log(p0num / p0totalnum)
    p1Vect = log(p1num / p1totalnum)

    return p0Vect, p1Vect, pAbusive


# 使用朴素贝叶斯进行分类
# 计算哪个出现的概率更大,sum(vec2Classify*p(w|ci))+logci -->vec2Classify是特征值向量->出现1,不出现0
#p(ci|w)=p(w|ci)p(ci)/p(w) p(w)相同,无需比较,所以只需要比较p(w|ci)p(ci)=>ln(p(w|ci)p(ci))=ln(p(w|ci))+ln(ci)
#=ln(p(w1|ci)p(w2|ci)...p(wn|ci))+ln(ci)=sum(ln(p(wi|ci))+ln(ci)=>sum(vec2Classify*piVect)+ln(ci)
#问题?如果特征值取值不光0或者1,而是更多值该如何计算???
def trainNB(vec2Classify, p0Vect, p1Vect, pAbusive):
    p1 = sum(vec2Classify * p1Vect) + log(pAbusive)
    p0 = sum(vec2Classify * p0Vect) + log(1.0 - pAbusive)

    if p1 > p0:
        return 1
    else:
        return 0


#将输入的一段字符串拆分成单词列表
def text2words(text):

    return [word.lower() for word in re.compile(r'\W+').split(text) if len(word) >2 ]


'''
测试贝叶斯算法
'''


def testBayes(postingList, classVec,vec2ClassifyList,factClassVec,desc):

    print('输入文档列表:\n', array(postingList))

    print('分类列表:\n', classVec)

    vocabList = createCabList(postingList)

    print('所有单词的列表:\n', vocabList)

    trainMatrix = getTrainMatrix(vocabList, postingList)

    print('单词是否出现的矩阵:\n', array(trainMatrix))

    p0Vect, p1Vect, pAbusive = trainNB0(array(trainMatrix), array(classVec))

    #print('非侮辱性文档中的单词出现的概率:\n', p0Vect)
    #print('侮辱性文档中的单词出现的概率:\n', p1Vect)
    #print('侮辱性文档出现的概率:\n', pAbusive)

    #vec2ClassifyList = ['dog', 'stupid']

    index=0
    trueCount=0
    totalCount=len(vec2ClassifyList)
    for vec2ClassifyElem in vec2ClassifyList:

        vec2Classify = setofWords2Vec(vocabList, vec2ClassifyElem)

        classResult = trainNB(array(vec2Classify), p0Vect, p1Vect, pAbusive)

        print('%s是否是%s的?0:不是 1:\n' % (vec2ClassifyElem,desc), classResult)

        if classResult ==factClassVec[index] :
           trueCount+=1
        index +=1

    print('正确率:\n',trueCount/float(totalCount))

def readDataSet(filepaths,start,end):
    postingList = []
    classVec = []
    for i in range(start, end):
        with open(filepaths[0] + '\%d.txt' % i, 'r') as fd:
            classVec.append(1)
            postingList.append(text2words(fd.read()))

        with open(filepaths[1] + '\%d.txt' % i, 'r') as fd:
            classVec.append(0)
            postingList.append(text2words(fd.read()))

    return postingList,classVec
#测试敏感词
vec2ClassifyList=[['stupid','uu']]

postingList, classVec = loadDataSet()
factClassVec=[1]
testBayes(postingList, classVec,vec2ClassifyList,factClassVec,'侮辱性')


#测试分类邮件
#垃圾邮件目录
spamPath='D:\software\python\sourcecode_and_data\MLiA_SourceCode\machinelearninginaction\Ch04\email\spam'
#非垃圾邮件目录
hamPath='D:\software\python\sourcecode_and_data\MLiA_SourceCode\machinelearninginaction\Ch04\email\ham'

filepaths=[spamPath,hamPath]

#读入文件,构造数据集和分类向量

postingList,classVec=readDataSet(filepaths,1,15)

#print("邮件数据集:\n",array(postingList))
#print("邮件分类向量\n",classVec)

#读入文件,构造测试数据,最好使用随机,这里只是简单测试

testPostingList,testClassVec=readDataSet(filepaths,15,26)




testBayes(postingList, classVec,testPostingList,testClassVec,'垃圾邮件')













 














  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值