朴素贝叶斯

上面我们提到贝叶斯决策理论要求计算两个概率 p1(x, y) 和 p2(x, y):
        如果 p1(x, y) > p2(x, y), 那么属于类别 1;
        如果 p2(x, y) > p1(X, y), 那么属于类别 2.

这并不是贝叶斯决策理论的所有内容。使用 p1() 和 p2() 只是为了尽可能简化描述,而真正需要计算和比较的是 p(c1|x, y) 和 p(c2|x, y) .这些符号所代表的具体意义是: 给定某个由 x、y 表示的数据点,那么该数据点来自类别 c1 的概率是多少?数据点来自类别 c2 的概率又是多少?注意这些概率与概率 p(x, y|c1) 并不一样,不过可以使用贝叶斯准则来交换概率中条件与结果。具体地,应用贝叶斯准则得到:            

使用上面这些定义,可以定义贝叶斯分类准则为:
        如果 P(c1|x, y) > P(c2|x, y), 那么属于类别 c1;
        如果 P(c2|x, y) > P(c1|x, y), 那么属于类别 c2.
在文档分类中,整个文档(如一封电子邮件)是实例,而电子邮件中的某些元素则构成特征。我们可以观察文档中出现的词,并把每个词作为一个特征,而每个词的出现或者不出现作为该特征的值,这样得到的特征数目就会跟词汇表中的词的数目一样多。


我们假设特征之间 相互独立 。所谓 独立(independence) 指的是统计意义上的独立,即一个特征或者单词出现的可能性与它和其他单词相邻没有关系,比如说,“我们”中的“我”和“们”出现的概率与这两个字相邻没有任何关系。这个假设正是朴素贝叶斯分类器中 朴素(naive) 一词的含义。朴素贝叶斯分类器中的另一个假设是,每个特征同等重要。

Note: 朴素贝叶斯分类器通常有两种实现方式: 一种基于伯努利模型实现,一种基于多项式模型实现。这里采用前一种实现方式。该实现方式中并不考虑词在文档中出现的次数,只考虑出不出现,因此在这个意义上相当于假设词是等权重的。

1.词表到向量的转换函数

from numpy import *
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']]
    classVec = [0,1,0,1,0,1]
    return postingList,classVec

#统计所有文档中出现的词条列表且无重复词条
def createVocabList(dataSet):
    vocabSet = set([])   #新建一个存放词条的集合
    for document in dataSet:  #遍历文档集合中的每一篇文档
         #将文档列表转为集合的形式,保证词条的唯一性。
        #然后与vocabSet取并集,向vocabSet中添加没有出现的新词条
        vocabSet = vocabSet | set(document)
    return list(vocabSet)  #再将集合转化为列表,便于接下来的处理

#根据词条列表中的词条是否在文档中出现(出现1,未出现0)将文档转化为词条向量
def setOfWords2Vec(vocabList,inputSet):
    returnVec = [0]*len(vocabList) #新建一个长度为vocabSet的列表,并各元素初始化为0
    for word in inputSet:     #遍历文档中的每一个词条
        if word in vocabList:  #如果词条在列表中出现
            #通过列表获取当前word的索引(下标)
            returnVec[vocabList.index(word)] = 1   #将词条向量中对应下标的项由0改为1
        else:
            print('the word: %s is not in my Vocabulary!'% word)
    return returnVec  #返回input转化后的词条向量

注:前两个函数加载后的结果:

    

    

2. 计算概率:

#训练算法,从词向量计算概率。
#@trainMatrix:由每篇文档的词条向量组成的文档矩阵
#@trainCategory:每篇文档的类标签组成的向量
def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)  #获取文档中的数目
    numWords = len(trainMatrix[0])   #获取词条向量的长度
    pAbusive = sum(trainCategory)/float(numTrainDocs) #所有文档中属于1类所占的比例(c=1)
    p0Num = ones(numWords);p1Num = ones(numWords) #创建一个长度为词条向量等长的数组
    p0Denom = 2.0; p1Denom = 2.0  #  分母初始化为0
    for i in range(numTrainDocs):  #遍历每一篇文档的词条向量
        if trainCategory[i] == 1:  #如果该词条向量对应的标签为1
            p1Num += trainMatrix[i]  #统计类别为1的词条向量中各个词条出现的次数
            p1Denom += sum(trainMatrix[i]) #统计类别为1的词条向量中出现的所有词条的总数
        else:                                #即属于侮辱类1的出现的所有数目
            p0Num += trainMatrix[i]     #统计类别为0的词条向量中各个词条出现的次数
            p0Denom += sum(trainMatrix[i])  #统计类别0所有文档中出现单词的数目
    p1Vect = log(p1Num/p1Denom)   #计算侮辱类1的概率即p(wi|c1)..
    p0Vect = log(p0Num/p0Denom)   #计算非侮辱类0的概率即p(wi|c0)...
    return p0Vect,p1Vect,pAbusive

3.  垃圾邮件测试

#文本解析及垃圾邮件测试
def textParse(bigString):
    import re
    #1.对长字符串进行分割,分割符为除单次和数字之位的任意字符
    listOfTokens = re.split(r'\W*',bigString)
    #2.将分割后的字符串所有大写字母变成小写lower(),且只保留单词长度大于3的单词
    return [tok.lower() for tok in listOfTokens if len(tok)>2]

def spamTest():
    docList=[];classList=[];fullText=[]
    for i in range(1,26):   #有25个txt文件
        #打开并读取目录下的文本的长字符串,并进行处理返回
        wordList = textParse(open('email/spam/%d.txt' % i).read())
        docList.append(wordList)  #将得到的字符串列表添加到doc列表中
        fullText.extend(wordList) #将得到的字符串列表中的元素加到fullText列表
        classList.append(1)       #类列表添加标签1
        #打开并取得另外一个类别为0的文件,然后进行处理
        wordList = textParse(open('email/ham/%d.txt' % i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    #将所有邮件中出现的字符串构建成字符串列表
    vocabList = createVocabList(docList)
    trainingSet = list(range(50));testSet = []
    for i in range(10):
        #随机选取1-50中的10个数,作为索引
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex]) #将选出的列表索引值加到test列表中
        del(trainingSet[randIndex])  #从整数列表中删除选出的数,防止下次再选
    trainMat = [];trainClasses = []
    for docIndex in trainingSet:  #遍历训练集中的每一个字符串列表
        #将字符串列表转为词条向量,添加到训练矩阵中
        trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
        trainClasses.append(classList[docIndex]) #将该邮件的类标签存入训练标签中
    p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:  #遍历测试机中字符串列表
        #同样将测试集中的字符串列表转为词条向量
        wordVector = setOfWords2Vec(vocabList,docList[docIndex])
        #对测试集字符串向量预测,分类结果不等于实际结果
        if classifyNB(array(wordVector),p0V,p1V,pSpam) !=classList[docIndex]:
            errorCount +=1
    print('the error rate is:',float(errorCount)/len(testSet))

注:random.uniform()方法返回二者之间的随机值。

trainingSet仅仅是个整数列表,无实际训练集文本数据,相当于一个索引列表,其需要转化为list对象,因为在其后三行左右有个del()操作,若不转化del()无法删除range对象,(range()函数返回的是range对象)。

fulltext列表在此代码中无意义。


4. RSS源分类器

#使用朴素贝叶斯分类器从个人广告中获取区域倾向
#RSS源分类器及高频词去除函数
def calcMostFreq(vocabList,fullText):
    import operator
    freqDict = {}
    for token in vocabList:
        #将单词/单词出现的次数作为键值对存入字典
        freqDict[token] = fullText.count(token)
    #按照键值(词条出现的次数)对字典由大到小排序
    sortedFreq = sorted(freqDict.items(),key=operator.itemgetter(1),reverse=True)
    return sortedFreq[:30]  #返回出现次数最多的前30个词

def localWords(feed1,feed0):
    import feedparser
    docList = [];classList = []; fullText =[]
    minLen = min(len(feed1['entries']),len(feed0['entries']))
    for i in range(minLen):
        wordList = textParse(feed1['entries'][i]['summary'])
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList = textParse(feed0['entries'][i]['summary'])
        docList.append(wordList)
        fullText.extend(wordList)
        classList.appeend(0)
    vocabList = createVocabList(docList)  #构建出现的搜友词条列表
    top30Words = calcMostFreq(vocabList,fullText)
    for pairW in top30Words:
        if pairW[0] in vocabList: #这里top30是个字典,所以pairW[0]是个键,这样的删除
            vocabList.remove(pairW[0])
    #下面与函数spamTest完全相同
    trainingSet = range(2*minLen); testSet =[]
    for i in range(20):
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex])
    trainMat = []; trainClasses = []
    for docIndex in trainingSet:
        trainMat.append(bagOfWords2VecMN(vocabList,docList[docIndex]))
        trainClasses.append(classesList[docIndex])
    p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:
        wordVector = bagOfWords2VecMN(vocabList,docList[docIndex])
        if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
            errorCount +=1
    print('the error rate is:',float(errorCount)/len(testSet))
    return vocabList,p0V,p1V

5.显示地域相关的用词

#最具表征性的词汇显示函数
def getTopWords(ny,sf):
    import operator
    vocabList,p0V,p1V = localWords(ny,sf) #利用RSS源分类器获取所有词条,以及每个分类中每个单词出现的概率
    topNY = []; topSF =[]
    for i in range(len(p0V)):  #遍历每个类中各个单词的概率值
        if p0V[i] > -6.0: #往相应元组列表中添加概率大于阈值的单词及其概率值组成的二元列表
            topSF.append((voacbList[i]),p0V[i])
        if p1V[i] > -6.0:
            topNY.append((vocabList[i]),p1V[i])
    #对列表按照每个二元列表中的概率值项进行排序,由大到小
    sortedSF =sorted(topSF,key=lambda pair:pair[1],reverse =True)
    print('SF****NY***')
    for item in sortedSF:#遍历列表中的每一个二元条目列表
        print(item[0])  #打印每个二元列表中的单词字符串元素
    sortedNY =sorted(topNY,key=lambda pair:pair[1],reverse =True)
    print('NY****NY***')
    for item in sortedNY:
        print(item[0])

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值