《机器学习实战》学习笔记第四章 —— 朴素贝叶斯

主要内容:

一.利用朴素贝叶斯进行文档分类

二.利用朴素贝叶斯进行垃圾邮件过滤

(这一章忍不住偷懒了,只做了代码的注释,羞愧羞愧,大懒鬼!)

一.利用朴素贝叶斯进行文档分类

  1 # coding:utf-8
  2 '''
  3 Created on Oct 19, 2010
  4 @author: Peter
  5 '''
  6 from numpy import *
  7 
  8 
  9 '''创造一些数据'''
 10 def loadDataSet():
 11     postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
 12                    ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
 13                    ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
 14                    ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
 15                    ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
 16                    ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
 17     classVec = [0, 1, 0, 1, 0, 1]  # 相应的标签,1是带有侮辱性的,0不带侮辱性
 18     return postingList, classVec
 19 
 20 '''创建单词表,先用set去重,然后再以list的形式返回'''
 21 def createVocabList(dataSet):
 22     vocabSet = set([])  # create empty set
 23     for document in dataSet:
 24         vocabSet = vocabSet | set(document)  # union of the two sets
 25     return list(vocabSet)
 26 
 27 '''返回一个01列表,表示单词表中的某个单词是否出现在inputSet中'''
 28 def setOfWords2Vec(vocabList, inputSet):
 29     returnVec = [0] * len(vocabList)
 30     for word in inputSet:
 31         if word in vocabList:
 32             returnVec[vocabList.index(word)] = 1
 33         else:
 34             print "the word: %s is not in my Vocabulary!" % word
 35     return returnVec
 36 
 37 '''文档词袋模型,即把原来“单词是否出现在文档上”改为“单词在文档上出现了几次”'''
 38 def bagOfWords2VecMN(vocabList, inputSet):
 39     returnVec = [0] * len(vocabList)
 40     for word in inputSet:
 41         if word in vocabList:
 42             returnVec[vocabList.index(word)] += 1   #把原先的 “=1”改为“+=1”
 43     return returnVec
 44 
 45 
 46 '''求出P(c1)、P(w|c1)、P(w|c0).   当P(c1)求出时,P(c0) = 1-P(c1)'''
 47 '''其中P(w|c1)是一个列表,等于[P(w1|c1),P(w2|c1),P(w3|c1)……],P(w|c0)也是一个列表;P(c0)为一个实数'''
 48 def trainNB0(trainMatrix, trainCategory):
 49     numTrainDocs = len(trainMatrix)     #训练数据集的大小,即第一维
 50     numWords = len(trainMatrix[0])      #一条训练数据集的特征数,也就是单词表的长度,即第二维
 51     pAbusive = sum(trainCategory) / float(numTrainDocs)  #P(c1)
 52     '''
 53         以下是计算P(w|c1)、P(w|c0)的初始化阶段。
 54         在计算P(w1|c1)*P(w2|c0)*……时,如果其中一个为0,那么结果就为0,为了降低这种影响,
 55         可将所有单词的出现次数初始化为1,并将坟墓初始化为2
 56     '''
 57     p0Num = ones(numWords)
 58     p1Num = ones(numWords)  # change to ones()
 59     p0Denom = 2.0
 60     p1Denom = 2.0  # change to 2.0
 61     ''''''
 62     for i in range(numTrainDocs):
 63         if trainCategory[i] == 1:
 64             p1Num += trainMatrix[i]
 65             p1Denom += sum(trainMatrix[i])
 66         else:
 67             p0Num += trainMatrix[i]
 68             p0Denom += sum(trainMatrix[i])
 69     '''
 70         以下是计算P(w|c1)、P(w|c0)的最终部分。
 71         在计算P(w1|c1)*P(w2|c0)*……时,由于太多很小的数相乘,很容易造成下溢,当四舍五入时结果就很可能为0,
 72         解决办法是对乘积取对数,就有:ln(ab) = lna+lnb把“小数相乘”转化为小数相加,避免了下溢。
 73         由于x与lnx在x>0处有相同的增减性,两者的最值不相同,但最值点是相同的,所以不会影响最终的分类。
 74     '''
 75     p1Vect = log(p1Num / p1Denom)  # P(w|c1)
 76     p0Vect = log(p0Num / p0Denom)  # P(w|c0)
 77     ''''''
 78     return p0Vect, p1Vect, pAbusive
 79 
 80 '''利用朴素贝叶斯进行分类,其中vec2Classify为输入数据,他是有关单词表的01串,
 81 p0Vec, p1Vec, pClass1则为trainNB0()的3个返回值,即P(w|c0)、P(w|c1)、P(c1)'''
 82 def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
 83     '''
 84         vec2Classify * p1Vec是什么意思?
 85         可知p1Vec为训练数据集中的P(w|c1),它是一个列表(对应着单词表)。在计算P(w|c1)时,每一个单词的概率即P(wi|c1)都计算了,
 86         但对于输入数据而言,有些单词出现了,有些单词没有出现,而我们只需要计算基础了的单词,所以要乘上系数ec2Classify
 87     '''
 88     '''
 89         sum(vec2Classify * p1Vec)计算的是P(w|c1),log(pClass1)计算的是P(c1)
 90         按照贝叶斯公式,理应还要减去P(w)的那一部分。但由于p1、p0都需要减去这一部分的值,
 91         且我们只需要比较p1、p0的大小而不需求求出具体的值,所以可以省去这一部分的计算
 92     '''
 93     p1 = sum(vec2Classify * p1Vec) + log(pClass1)  # element-wise mult
 94     p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
 95     if p1 > p0:
 96         return 1
 97     else:
 98         return 0
 99 
100 
101 def testingNB():
102     listOPosts, listClasses = loadDataSet()         #提取数据
103     myVocabList = createVocabList(listOPosts)
104     trainMat = []
105     for postinDoc in listOPosts:        #数据加工,trainMat、listClasses为训练数据集,其中trainMat为特征X,listClasses为标签Y
106         trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
107     p0V, p1V, pAb = trainNB0(array(trainMat), array(listClasses))       #计算出概率P(c1)、P(w|c1)、P(w|c0)
108     testEntry = ['love', 'my', 'dalmation']     #测试数据
109     thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
110     print testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb)
111     testEntry = ['stupid', 'garbage']
112     thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
113     print testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb)
114 
115 testingNB()

三.利用朴素贝叶斯进行垃圾邮件过滤

  1 # coding:utf-8
  2 
  3 from numpy import *
  4 
  5 '''创建单词表,先用set去重,然后再以list的形式返回'''
  6 def createVocabList(dataSet):
  7     vocabSet = set([])  # create empty set
  8     for document in dataSet:
  9         vocabSet = vocabSet | set(document)  # union of the two sets
 10     return list(vocabSet)
 11 
 12 '''文档词袋模型,即把原来“单词是否出现在文档上”改为“单词在文档上出现了几次”'''
 13 def bagOfWords2VecMN(vocabList, inputSet):
 14     returnVec = [0] * len(vocabList)
 15     for word in inputSet:
 16         if word in vocabList:
 17             returnVec[vocabList.index(word)] += 1   #把原先的 “=1”改为“+=1”
 18     return returnVec
 19 
 20 '''求出P(c1)、P(w|c1)、P(w|c0).   当P(c1)求出时,P(c0) = 1-P(c1)'''
 21 '''其中P(w|c1)是一个列表,等于[P(w1|c1),P(w2|c1),P(w3|c1)……],P(w|c0)也是一个列表;P(c0)为一个实数'''
 22 def trainNB0(trainMatrix, trainCategory):
 23     numTrainDocs = len(trainMatrix)     #训练数据集的大小,即第一维
 24     numWords = len(trainMatrix[0])      #一条训练数据集的特征数,也就是单词表的长度,即第二维
 25     pAbusive = sum(trainCategory) / float(numTrainDocs)  #P(c1)
 26     '''
 27         以下是计算P(w|c1)、P(w|c0)的初始化阶段。
 28         在计算P(w1|c1)*P(w2|c0)*……时,如果其中一个为0,那么结果就为0,为了降低这种影响,
 29         可将所有单词的出现次数初始化为1,并将坟墓初始化为2
 30     '''
 31     p0Num = ones(numWords)
 32     p1Num = ones(numWords)  # change to ones()
 33     p0Denom = 2.0
 34     p1Denom = 2.0  # change to 2.0
 35     ''''''
 36     for i in range(numTrainDocs):
 37         if trainCategory[i] == 1:
 38             p1Num += trainMatrix[i]
 39             p1Denom += sum(trainMatrix[i])
 40         else:
 41             p0Num += trainMatrix[i]
 42             p0Denom += sum(trainMatrix[i])
 43     '''
 44         以下是计算P(w|c1)、P(w|c0)的最终部分。
 45         在计算P(w1|c1)*P(w2|c0)*……时,由于太多很小的数相乘,很容易造成下溢,当四舍五入时结果就很可能为0,
 46         解决办法是对乘积取对数,就有:ln(ab) = lna+lnb把“小数相乘”转化为小数相加,避免了下溢。
 47         由于x与lnx在x>0处有相同的增减性,两者的最值不相同,但最值点是相同的,所以不会影响最终的分类。
 48     '''
 49     p1Vect = log(p1Num / p1Denom)  # P(w|c1)
 50     p0Vect = log(p0Num / p0Denom)  # P(w|c0)
 51     ''''''
 52     return p0Vect, p1Vect, pAbusive
 53 
 54 '''利用朴素贝叶斯进行分类,其中vec2Classify为输入数据,他是有关单词表的01串,
 55 p0Vec, p1Vec, pClass1则为trainNB0()的3个返回值,即P(w|c0)、P(w|c1)、P(c1)'''
 56 def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
 57     '''
 58         vec2Classify * p1Vec是什么意思?
 59         可知p1Vec为训练数据集中的P(w|c1),它是一个列表(对应着单词表)。在计算P(w|c1)时,每一个单词的概率即P(wi|c1)都计算了,
 60         但对于输入数据而言,有些单词出现了,有些单词没有出现,而我们只需要计算基础了的单词,所以要乘上系数ec2Classify
 61     '''
 62     '''
 63         sum(vec2Classify * p1Vec)计算的是P(w|c1),log(pClass1)计算的是P(c1)
 64         按照贝叶斯公式,理应还要减去P(w)的那一部分。但由于p1、p0都需要减去这一部分的值,
 65         且我们只需要比较p1、p0的大小而不需求求出具体的值,所以可以省去这一部分的计算
 66     '''
 67     p1 = sum(vec2Classify * p1Vec) + log(pClass1)  # element-wise mult
 68     p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
 69     if p1 > p0:
 70         return 1
 71     else:
 72         return 0
 73 
 74 def textParse(bigString):  # 提取、处理、过滤单词
 75     import re
 76     listOfTokens = re.split(r'\W*', bigString)
 77     return [tok.lower() for tok in listOfTokens if len(tok) > 2]
 78 
 79 def spamTest():
 80     docList = []
 81     classList = []
 82     fullText = []
 83     for i in range(1, 26):
 84         wordList = textParse(open('email/spam/%d.txt' % i).read())
 85         docList.append(wordList)
 86         fullText.extend(wordList)
 87         classList.append(1)
 88         wordList = textParse(open('email/ham/%d.txt' % i).read())
 89         docList.append(wordList)
 90         fullText.extend(wordList)
 91         classList.append(0)
 92     vocabList = createVocabList(docList)  # 创建单词表
 93     trainingSet = range(50)
 94     testSet = []  # 从50条数据中随机选出10个作为测试数据,trainingSet和testSet存的都是下标,对应在docList和classList上
 95     for i in range(10):
 96         randIndex = int(random.uniform(0, len(trainingSet)))
 97         testSet.append(trainingSet[randIndex])
 98         del (trainingSet[randIndex])
 99     trainMat = []
100     trainClasses = []
101     for docIndex in trainingSet:  # 剩下的的都作为训练数据集
102         trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
103         trainClasses.append(classList[docIndex])
104     p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))    #计算出概率P(c1)、P(w|c1)、P(w|c0)
105     errorCount = 0
106     for docIndex in testSet:  # 进行测试
107         wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
108         if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
109             errorCount += 1
110             print "classification error", docList[docIndex]
111     print 'the error rate is: ', float(errorCount) / len(testSet)
112     # return vocabList,fullText
113 
114 
115 spamTest()

 

猜你喜欢

转载自www.cnblogs.com/DOLFAMINGO/p/9445812.html