机器学习实战--基于概率论的分类方法:朴素贝叶斯(一)

优点:在数据较少的情况下仍然有效,可以处理多类别问题。

缺点:对于输入数据的准备方式较为敏感。

1.使用条件概率来分类:

两个概率p1(x,y)和p2(x,y):

如果 p1(x,y)>p2(x,y),则属于类别1,反之属于类别2.上述只是尽可能简化的描述,真正需要比较和计算的是p(c1|x,y)和p(c2|x,y),意义是对于给定的数据点x,y,该数据点来自类别c1和c2的概率,可以shiyoong贝叶斯来交换概率中的条件与结果。

p(ci|x,y) = [p(x,y|ci)p(ci)]/p(x,y)

如此便可以通过三个已知的概率论值来计算未知的概率论值。

2.使用python进行文本分类:

先拆分文本,从文本中获取特征,这些特征就是来自文本的词条,将每一个文本片段表示为一个词条向量,1代表词条出现在片段中,0代表没有出现。

2.1 准备数据:从文本中构建词向量

将文本看成单词向量或词条向量,首先考虑出现在所有文档中的所有单词,在决定将哪些词纳入词汇表,然后必须将每一篇文档转换为词汇表上的向量。

from numpy import *
from math import log
#词表到向量的转换函数
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']]
    #1代表侮辱性文字,0代表正常言论
    classVec = [0,1,0,1,0,1]
    return postingList,classVec
#将多个数据列表整合到单个无重复元素列表中
def createVocabList(dataSet):
    vocabSet = set([])
    for document in dataSet:
        #取两个集合的并集
        vocabSet = vocabSet | set(document)
    return list(vocabSet)
#将词列表转换为向量
def setOfWord2Vec(vocabList,inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            #将词集中对应单词的的索引值置为1
            returnVec[vocabList.index(word)]=1
        else:print("the word:%s is not in my Vocabulary"%word)
    return returnVec

createVocabList()会创建一个包含在所有文档中出现的不重复词的列表。使用了set数据结构,将词条列表传递给set构造函数会返回一个不重复的词表。

2.2训练算法:从词向量计算概率

重写贝叶斯准则,将x,y替换为w,w表示为一个向量,即它由多个数值组成,当前例子中数值的个数与词个数相同。

p(ci|w)=p(w|ci)p(ci)/p(w)

首先可以通过类别i中的文档数/总文档数来计算概率p(ci),接下来计算p(w|ci),如果将w展开为一个个独立特征,那么就可以将上述概率写为p(w0,w1...wn|ci),这里假设所有数值相互独立,条件独立假设可以通过p(w0|ci)p(w1|ci)...p(wn|ci)来计算上述概率。

#朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    #得到概率p(x=1)
    pAbusive = sum(trainCategory)/float(numTrainDocs)
    p0Num = zeros(numWords)
    p1Num = zeros(numWords)
    p0Denom = 0.0
    p1Denom = 0.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 = p1Num/p1Denom
    p0Vect = p0Num/p0Denom
    return p0Vect,p1Vect,pAbusive

输入参数为文档矩阵trainMatrix,以及由每篇文档类别标签所构成的向量trainCategory,首先计算文档属于侮辱性文档的概率p(class=1) ,遍历trainMarix中的所有文档,分别统计该类别中词的总个数和各个词数值出现的次数,最后将次数/总个数得到两个类别的各词的概率。值得注意的是:用一个数组除以浮点数的操作在常规python列表中很难实现,因此借用numpy矩阵。

2.3测试算法:根据现实情况修改分类器

要计算该类别多个概率的乘积以获得文档属于类别的概率,即计算p(w0|ci)p(w1|ci)...p(wn|ci)。如果其中一个概率值为0,最后乘积也为0,可以将所有词出现的次数初始化为1,并将分母初始化为2.

p0Num = ones(numWords);p1Num = ones(numWords);

p0Debom = 2;p1Denom = 2

另外太多很小的数相乘会下溢出,因此可以对乘积取自然对数。

#朴素贝叶斯分类函数
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    #分别得到p(y=1|x)和p(y=0|x)的概率
    p1 = sum(vec2Classify*p1Vec) + log(pClass1)
    p0 = sum(vec2Classify*p0Vec) + log(1-pClass1)
    if p1 > p0:
        return 1
    else:
        return 0
#对给定的数据集进行测试
def testingNB():
    listOPosts,listClasses = loadDataSet()
    myVocablist = createVocabList(listOPosts)
    trainMat = []
    for postinDoc in listOPosts:
        trainMat.append(setOfWord2Vec(myVocablist,postinDoc))
    p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
    testEntry = ['love','my','dalmation']
    thisDoc = array(setOfWord2Vec(myVocablist,testEntry))
    print(testEntry,'classifed as:',classifyNB(thisDoc,p0V,p1V,pAb))
    testEntry = ['stupid','garbage']
    thisDoc = array(setOfWord2Vec(myVocablist,testEntry))
    print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))

array函数是从常规的python数列和元组创建Numpy矩阵的形式。vec2Classify*p1Vec是求内继,将各个数值与其对应的特征犬只相乘,即得到该词向量的在确定类别下的概率,通过比较在两个类别下的概率大小确定该词向量属于哪个类别。

2.4文档词袋模型

将每个词出现与否作为特征的描述称为词集模型。一个词在词中出现多次这种情况在词集中无法被描述,描述词在词典中出现次数的模型是词袋模型。

# 朴素贝叶斯词袋模型
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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值