朴素贝叶斯——文本分类

1.1、贝叶斯定理

        贝叶斯定理是关于随机事件A和B的条件概率的一则定理。

其中P(A|B)是在B发生的情况下A发生的可能性。

在贝叶斯定理中,每个名词都有约定俗成的名称:

  • P(A|B)是已知B发生后A的条件概率,也由于得自B的取值而被称作A的后验概率
  • P(B|A)是已知A发生后B的条件概率,也由于得自A的取值而被称作B的后验概率
  • P(A)是A的先验概率或(或边缘概率)。之所以称为"先验"是因为它不考虑任何B方面的因素。
  • P(B)是B的先验概率或边缘概率。

按这些术语,贝叶斯定理可表述为:后验概率 = (相似度*先验概率)/标准化常量。也就是说,后验概率与先验概率和相似度的

乘积成正比。另外,比例P(B|A)/P(B)也有时被称作标准相似度(standardised likelihood),贝叶斯定理可表述为:

后验概率 = 标准相似度*先验概率

1.2、分类问题

分类是指识别出样本所属的类别。识别前是否需要进行训练,可分为有监督分类无监督分类。有监督分类(supervised classification):

根据已知训练区提供的样本,通过计算选择特征参数,建立判别函数以对样本进行的分类。无监督分类(unsupervised classification):指人们

事先对分类过程不施加任何的先验知识,而仅凭数据,即自然聚类的特性,进行“盲目”的分类;其分类的结果只是对不同类别达到了区分,但

并不能确定类别的属性。

1.3、朴素贝叶斯分类器

分类是把一个事物分到某个类别中。一个事物具有很多属性,把它的众多属性看作一个向量,即x=(x1,x2,x3,…,xn),用x这个向量

来代表这个事物,x的集合记为X,称为属性集。类别也有很多种,用集合C={c1,c2,…cm}表示。一般XC的关系是不确定的,可以将

XC看作是随机变量,P(C|X)称为C的后验概率,与之相对的,P(C)称为C的先验概率。

根据贝叶斯公式,后验概率P(C|X)=P(X|C)P(C)/P(X),但在比较不同C值的后验概率时,分母P(X)总是常数,忽略掉,后验概率

P(C|X)=P(X|C)P(C),先验概率P(C)可以通过计算训练集中属于每一个类的训练样本所占的比例,容易估计,对类条件概率P(X|C)的估

计,这里我只说朴素贝叶斯分类器方法,因为朴素贝叶斯假设事物属性之间相互条件独立,P(X|C)=P(xi|ci)

2.1、使用朴素贝叶斯进行文档分类

        机器学习的一个重要过程就是文档的自动分类。在文档分类中,整个文档(如一封电子邮件)是实例,而电子邮件中的某些元

素构成特征。虽然电子邮件是一种不会增加的文本,但同样也可以对新闻报导、用户留言等其他任意文本进行分类。观察文档中出

现的词,并把每个词的出现作为一个特征,这样得到的特征数目就会跟词汇表中的词一样多。

        朴素贝叶斯的一般过程:

  1. 收集数据:可以用任何方法
  2. 准备数据
  3. 分析数据:有大量特征时,绘制特征作用不大,此时用直方图效果更好。
  4. 训练算法:计算不同的独立特征的条件概率。
  5. 测试算法:计算错误率。
  6. 使用算法:一个常见的朴素贝叶斯应用是文档分类。可以在任意的分类场景中使用朴素贝叶斯分类器,不一定是文本。
        两个假设:
        1、特征之间相互独立,即一个特征或单词的出现的可能性和它与其他单词相邻没有关系。例如 am 出现在第一人称I 和第三人

人称单词He之后的概率没有关系。显然根据正常的语法规则,am 在 I 之后的概率肯定比 He高。所以称之为 naive
    
            2、每个特征同等重要

2.2、程序分析:

2.2.1、首先,将文本转化成单词表,第二个函数返回一个向量,矩阵元素初始全为0,当词汇表vocabuList 中词汇出现在inputSet

时, 将对应位置的向量元素改为1.
def createVocabList(dataSet):
    vocabSet = set([])  #create empty set
    for document in dataSet:
        vocabSet = vocabSet | set(document) #union of the two sets
    return list(vocabSet)

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

2.2.2、训练算法
首先是概率的计算,p(Ci|w)=p(w|Ci)*p(Ci)/p(w)

              其中,w是一个向量,表示一个词汇表,p(Ci)表示为第i类文档的概率,本文中i取值为0、1,分别表示正常邮件和垃圾邮件,这

个概率可以由统计方法得到。即第i类文档的数量与文档总数的比值。如何计算p(w|Ci)呢,正如之前的假设,w的各个特征相互独立

也就是说,p(w|Ci)=p(w1|Ci)p(w2|Ci)...p(wN|Ci),其中Wn是向量w的分量。如此:
def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    pAbusive = sum(trainCategory)/float(numTrainDocs)
    p0Num = zeros(numWords); p1Num = zeros(numWords)
    #p0Num = ones(numWords); p1Num = ones(numWords)      #change to ones() 
    p0Denom = 0.0; p1Denom = 0.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 = p1Num/p1Denom
    p0Vect = p0Num/p0Denom
    '''
    p1Vect = log(p1Num/p1Denom)          #change to log()
    p0Vect = log(p0Num/p0Denom)          #change to log()
    '''

    return p0Vect,p1Vect,pAbusive

2.2.3、请看代码注释
#根据p1与p0概率的大小关系将文本分类
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): 
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)    #element-wise mult
    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else: 
        return 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


#一个测试函数,可以修改测试词组
def testingNB():
    listOPosts,listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
    testEntry = ['love', 'my', 'dalmation']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
    testEntry = ['stupid', 'garbage']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)


#切分邮件文本,使用正则表达式,去掉符合、数字,替换大写字母为小写,将文本处理为一个单词表。
def textParse(bigString):    #input is big string, #output is word list
    import re
    listOfTokens = re.split(r'\W*', bigString)
    return [tok.lower() for tok in listOfTokens if len(tok) > 2] 

#交叉验证,将两个文件夹中的50条文本全部读入并处理为单词表,随机选择10条文本,剩下40条作为测试集    
def spamTest():
    docList=[]; classList = []; fullText =[]
    for i in range(1,26):
        wordList = textParse(open('email/spam/%d.txt' % i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList = textParse(open('email/ham/%d.txt' % i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    vocabList = createVocabList(docList)#create vocabulary
    trainingSet = range(50); testSet=[]           #create test set
    for i in range(10):
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex])  
    trainMat=[]; trainClasses = []
    for docIndex in trainingSet:#train the classifier (get probs) trainNB0
        trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:        #classify the remaining items
        wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
        if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
            errorCount += 1
            print "classification error",docList[docIndex]
    print 'the error rate is: ',float(errorCount)/len(testSet)
    #return vocabList,fullText



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值