机器学习实战读书笔记-朴素贝叶斯

朴素贝叶斯

朴素贝叶斯是一种基于概率论的分类方法

条件概率公式

P(Y|X)=P(X|Y)P(Y)P(X)

P(Y|X)表示,X条件下Y的概率。

举例说明:假设夫妻双方血型,丈夫为O型,妻子为AB型血。两人结合生下的孩子是什么血型?

丈夫血型妻子血型孩子的血型
aaAB

P(A型血|(aa,AB))表示孩子是A型血的概率,其中(丈夫为O型,妻子为AB型血即为条件)

其中P(X|Y)在各特征独立且权重一样的的情况下可以拆分成:

P(X|Y)=P((x1,x2...xn)|Y)=P((x1)|Y)P((x2)|Y)...P((xn)|Y)

注意X为特征向量,可以有多个特征。如下

x1x2x3x4y
0110yes
0200yes
1110no
2110yes

X表示每一行的(x1,x2,x3,x4), Y表示每一行的y

这就很清楚了,

P((x1,x2...xn)|Y)=P((x1)|Y)P((x2)|Y)...P((xn)|Y)

左边表示x1,x2…xn同时满足,右边则是拆分满足x1的情况,再满足x2等等。所以上述等式成立是显而易见的了。

根据以上的概率知识,只要获得给定X的情况下,P(Y|X)概率最大的,那个Y就是我们需要的分类了。

算法实现步骤

  • 收集数据(初始化数据)
  • 获取训练集中,所有不同的词列表(多少个不同的词)
  • 转化为训练集矩阵形式
  • 训练算法,计算不同的独立词中各种分类情况下的概率
  • 给定某一串文字,进行分类得出结果

下面以文本分类作为例子进行说明(以在线社区的留言板为例):

具体实现

def testingNB():
    listOPosts, listClasses = loadDataSet() #初始化数据集及分类集
    myVocabList = createVocabList(listOPosts)  # 获得训练集中,所有不同的词列表即词汇表
    # 转化训练集为矩阵
    trainMat = []
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))

    p0V, p1V, pAb = AlgorithmUtil.trainNBO(array(trainMat), array(listClasses))

    # testEntry = ['love', 'my', 'dalmation']
    testEntry = ['dog', 'stupid', 'him']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))

    print testEntry,'classified as: ',AlgorithmUtil.classifyNB(thisDoc,p0V,p1V,pAb)

==========以下为一些子函数

#初始化训练数据
def loadDataSet():
    postingLis = [['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 postingLis, classVec

上面为初始训练集。当然实际情况不可能这么简单,这么少的。当然这不影响算法的实现步骤。

#获得包含在所有文档中出现的不重复词的列表(也就是获取词汇表)
def createVocabList(dataSet):
    #参数说明,dataSet可以看作上一函数中的postingLis,就是初始训练集
    vocabSet = set([])
    for document in dataSet:
        vocabSet = vocabSet | set(document) #并集
    return list(vocabSet)
#转化为词向量,向量的每一元素为1或0,分别表示词汇表中的单词在输人文档中是否出现
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] =1
        else: print "the word:%s is not in my Vocabulary!" % word
    return returnVec
#朴素贝叶斯分类器训练函数(只有俩类的情况)
def trainNBO(trainMatrix,trainCategory):
#参数说明,trainMatrix
    numTrainDocs = len(trainMatrix) #行
    numWords = len(trainMatrix[0]) #列
    pAbusive = sum(trainCategory) / float(numTrainDocs) #整个训练集中,侮辱性言论的比例,或者概率。P(Y),即P(侮辱性言论)
    p0Num = ones(numWords); p1Num = ones(numWords)
    # 1 代表侮辱性文字,0代表正常言论
    #p0Num表示训练集中,正常言论里面包含每一个词的个数。是一个向量(包括词汇表中每一个词)
    #p1Num表示训练集中,侮辱性言论里面包含每一个词的个数是一个向量(包括词汇表中每一个词)

    p0Denom = 2.0; p1Denom = 2.0
    #p0Denom表示训练集中,正常言论里面总的词汇数(有可能重复)
    #p1Denom表示训练集中,侮辱性言论里面总的词汇数(有可能重复)
    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 = np.log(p1Num/p1Denom) #概率 分类1时,各词出现的概率
    p0Vect = np.log(p0Num/p0Denom) #概率 分类0时,各词出现的概率

    #加log,是为一些数学到考虑,下面会提到

    return p0Vect, p1Vect, pAbusive

为什么p0Num,p1Num初始化为[1,1,….,1],不为[0,0,…,0]呢?
为什么p0Denom,p1Denom初始化为2呢?

是因为:利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率。从上面的函数我们可以看到,其实求到的是每一个词汇对应类别的概率。如果其中一个概率值为0,那么最后的乘积也为0。所以为降低 这种影响,可以将所有词的出现数初始化为1,并将分母初始化为2(分母不能为0吧)。这不影响结果,因为我们是要比较哪种分类的概率大

为什么要加得到的概率要log?

是因为:同样到要计算多个概率的乘积以获得文档属于某个类别的概率。由于大部分因子都非常小,所以程序会下溢出或者 得到不正确的答案。(很多很小到数相乘,四舍五入后会=0)。log不影响结果,因为我们是要比较哪种分类的概率大,log大的,还是大,趋势一致。(这应该好理解吧。。。)其实后面分解也会有用到。

#具体分类
def classifyNB(vec2Classify, pOVec, plVec, pClassl):
    #参数说明 
    #vec2Classify 测试文本(转换为向量后的)
    #pOVec 训练集中,类别为0即正常言论里,各词的概率
    #plVec 训练集中,类别为1即侮辱言论里,各词的概率
    #pClassl 训练集中,侮辱言论的概率
    pl = sum(vec2Classify * plVec) + log(pClassl)
    p0 = sum(vec2Classify * pOVec) + log(1.0 - pClassl)
    if pl > p0:
        return 1
    else: return 0

上面pl = sum(vec2Classify * plVec) + log(pClassl)的含义:

P(Y|X)=P(X|Y)P(Y)P(X)

根据 P(X|Y)=P((x1,x2...xn)|Y)=P((x1)|Y)P((x2)|Y)...P((xn)|Y)

因为X是相同的,分母相同,取log,只要比较分子的大小即可。
log一下,就得到了(简单,自己推导一下)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值