朴素贝叶斯,基本思想就是,给出一个分类问题,对于待求项,属于哪个分类的概率最大,那这个待求项就属于哪个分类。

给出基本公式

假设要分类物有n个特征,分别为F1、F2、F3、…、Fn,现在有m个类别分别是C1、C2、C3、…、Cm.贝叶斯就是计算出概率最大的那个分类。

具体贝叶斯定理参考http://zh.wikipedia.org/wiki/%E8%B4%9D%E5%8F%B6%E6%96%AF%E5%AE%9A%E7%90%86

对于多个特征,我们进行求解。

P(C|F1F2...Fn)= P(F1F2...Fn|C)P(C) / P(F1F2...Fn)

解释也就是,在都有这些特征的基础上属于类别C的概率等于在已知是C类,含有这些特征的概率乘以该分类是C类的概率,最终除以该分类物都含有这些特征的概率。

好,对于P(F1F2...Fn)对所有的分类物都是一样的,这样问题就可以简化为求

P(F1F2...Fn|C)P(C)的最大值。

而对于朴素贝叶斯来说,它更简化了,它认为分类物所有的特征都是独立的。这样我们就可以进一步简化为:

P(F1F2...Fn|C)P(C)= P(F1|C)P(F2|C) ... P(Fn|C)P(C)

这样我们的计算就变得简单很多了,在给定分类下某个特征发生的概率,这个我们根据样本数据是可以得到的。左边就可以计算出来。

虽然现实中可能这些所有的特征都相互独立,不过通过这样的假设求出的结果还是比较准确的。

这边是假设相互独立,而如果假设一个特征只与前面一个特征或者i个特征有关的话,那这个又转化成马尔科夫的问题。

好,那下面就通过Python代码来进一步的了解这个问题。这是一个社区留言板的例子,主要就是对文本进行分类,对有侮辱性的言论的文本进行屏蔽。

   1: #-*- coding: utf-8 -*
   2:   #导入数据 postingList对应社区的6条留言,[0,1,0,1,0,1]对应于2、4、6句是侮辱性语句,即所属类别
   3:  def loadDataSet():
   4:      postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
   5:                   ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
   6:                   ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
   7:                   ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
   8:                   ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
   9:                   ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
  10:      classVec = [0,1,0,1,0,1]  
  11:      return postingList,classVec
  12:   
  13:   #得到词汇表
  14:  def createVocabList(dataSet):
  15:      vocabSet = set([])  #set是不重复集
  16:      for document in dataSet:
  17:          vocabSet = vocabSet | set(document) #对每个文档求得的结果求并,去重复的
  18:      return list(vocabSet)#转换成list
  19:   
  20:  #根据词汇表构成0向量,对每个文档每个词对应向量中的位置赋值为1
  21:  def setOfWords2Vec(vocabList, inputSet):
  22:      returnVec = [0]*len(vocabList)#构建vocabList长度的0向量
  23:      for word in inputSet:
  24:          if word in vocabList:
  25:              returnVec[vocabList.index(word)] = 1
  26:          else: print "the word: %s is not in my Vocabulary!" % word
  27:      return returnVec

上述代码所做的事情是找出所有文档中所有不重复的词,构成词汇表,根据词汇表及其长度构建每个文档的词向量(文档中的词对应词汇表中的位置为1,在这边没有考虑这个词在文档中出现了几次,只考虑了这个词在文档中是否出现,没有考虑不同的词的权重不一样,后续讨论)。

得到如下结果,比如第一个文档的词向量

   1:  >>> import bayes
   2:  >>> listOPosts,listClasses = bayes.loadDataSet()
   3:  >>> myVocabList = bayes.createVocabList(listOPosts)
   4:  >>> bayes.setOfWords2Vec(myVocabList,listOPosts[0])
   5:  [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1]

 

下面给出计算每一个词在每个类别下的概率。

   1:   
   2:  def trainNB0(trainMatrix,trainCategory):
   3:      numTrainDocs = len(trainMatrix)# 6
   4:      numWords = len(trainMatrix[0])#得到词汇表的长度32
   5:      pAbusive = sum(trainCategory)/float(numTrainDocs)#(0+1+0+1+0+1)/6=0.5
   6:      p0Num = zeros(numWords)#长度为numWords32全为0的数组
   7:      p1Num = zeros(numWords)     
   8:      p0Denom = 0.0
   9:      p1Denom = 0.0                       
  10:      for i in range(numTrainDocs):
  11:          if trainCategory[i] == 1:
  12:              p1Num += trainMatrix[i]
  13:              p1Denom += sum(trainMatrix[i])
  14:          else:
  15:              p0Num += trainMatrix[i]
  16:              p0Denom += sum(trainMatrix[i])
  17:      p1Vect = p1Num/p1Denom         
  18:      p0Vect = p0Num/p0Denom         
  19:      return p0Vect,p1Vect,pAbusive

结果

   1:  >>> import bayes
   2:  >>> trainMatrix,trainCategory = bayes.getTrainMatrix()
   3:  >>> p0V,p1V,pAb = bayes.trainNB0(trainMatrix,trainCategory)
   4:  >>> p0V
   5:  array([ 0.04166667,  0.04166667,  0.04166667,  0.        ,  0.        ,
   6:          0.04166667,  0.04166667,  0.04166667,  0.        ,  0.04166667,
   7:          0.04166667,  0.04166667,  0.04166667,  0.        ,  0.        ,
   8:          0.08333333,  0.        ,  0.        ,  0.04166667,  0.        ,
   9:          0.04166667,  0.04166667,  0.        ,  0.04166667,  0.04166667,
  10:          0.04166667,  0.        ,  0.04166667,  0.        ,  0.04166667,
  11:          0.04166667,  0.125     ])
  12:  >>> p1V
  13:  array([ 0.        ,  0.        ,  0.        ,  0.05263158,  0.05263158,
  14:          0.        ,  0.        ,  0.        ,  0.05263158,  0.05263158,
  15:          0.        ,  0.        ,  0.        ,  0.05263158,  0.05263158,
  16:          0.05263158,  0.05263158,  0.05263158,  0.        ,  0.10526316,
  17:          0.        ,  0.05263158,  0.05263158,  0.        ,  0.10526316,
  18:          0.        ,  0.15789474,  0.        ,  0.05263158,  0.        ,
  19:          0.        ,  0.        ])

这边我添加了一个函数

   1:  def getTrainMatrix():
   2:      listOPosts,listClasses = loadDataSet()
   3:      myVocabList = createVocabList(listOPosts)
   4:      trainMat = []
   5:      for postinDoc in listOPosts:
   6:          trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
   7:      return trainMat,listClasses

 

这边其实是有问题的,之所有这边没有直接套用贝叶斯公式,因为这边计算单个词在某个类别下的概率为0很正常,具体看公式

P(c0|w)=P(w|c0)P(c0)/P(w)

在计算P(w|c0) = p(w0,w1,w2…,wn|c0),这边为朴素贝叶斯,则考虑w相互独立,

则P(w|c0) = P(w0|c0).P(w1|c0)…….P(wn|c0)

而其中任意一个wi在某个类别下不出现很正常,则P(wi|c0)就为0,则P(c0|w)= 0,显然这个不是我们想要的。

为了降低这种影响,我们将所有词出现初始化为1,并将分母初始化为2

修改部分如下:

   1:  p0Num = ones(numWords)#长度为numWords32全为1的数组
   2:  p1Num = ones(numWords)     
   3:  p0Denom = 2.0
   4:  p1Denom = 2.0  

因为由于是计算机浮点型运算会有精度问题,比如多个很小数相乘最终会四舍五入为0,如下:

   1:  0.0000034*0.00000023*0.000000045*0.00000000045*0.00000000000000045*0.0000000000000034*0.0000000000000000000000000000000000000001*0.00000000000000000000000001*0.000000000000000000000001*0.000000000000000000000000000000000000000000000000000000000000000000000000000000001*0.00000000000000000000000000000000000000000001*0.0000000000000000000000000000000000000000000001*0.00000000000000000000000000001
   2:  0.0

这个我们一般的处理办法是通过取对数的方式。这样小数就可以转化大值类型的数,避免最后的四舍五入,可以看如下:

   1:  >>> log(0.00000000000000000000000000000000000000000001)
   2:  -101.31374409173802

则把源代码修改如下:

   1:  p1Vect = log(p1Num/p1Denom)          #change to log()
   2:  p0Vect = log(p0Num/p0Denom)          #change to log()

 

另外要说明的是取对数了不影响函数的单调性,形象一点可以看下图:

机器学习3朴素贝叶斯

这几个问题解决后,下面开始写出最后的分类算法,,继续给出点公式,我们知道

P(w|c0)P(c0) = P(w0|c0).P(w1|c0)…….P(wn|c0)P(c0)

这样两边取对数

ln(P(w|c0)P(c0)) = ln((w0|c0))+ln(P(w1|c0))+……+ln(P(wn|c0))+ln(P(c0))

之前说了,对于P(w)大家一样,要求的话通过全概率公式即可以求。我们就不求了。

由于函数加ln不影响函数单调性,这样对于P(c|w)我们只要求ln((w0|c0))+ln(P(w1|c0))+……+ln(P(wn|c0))+ln(P(c0))

而每一个ln(wi|ci)我们已经求出。这样对于一个新的w,我们看w中有哪些wi,这样我们构建一个词汇表大小的向量,对i位赋值为1,其它位赋值为0,我们通过向量相乘,这样就可以求得每一个ln((wi|ci),然后相加,最后再加上ln(ci)就可以求得。

代码如下:

   1:  def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
   2:      p1 = sum(vec2Classify * p1Vec) + log(pClass1)    
   3:      p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
   4:      if p1 > p0:
   5:          return 1
   6:      else: 
   7:          return 0

最后我们给出测试函数:

   1:  def testingNB():
   2:      listOPosts,listClasses = loadDataSet()
   3:      myVocabList = createVocabList(listOPosts)
   4:      trainMat=[]
   5:      for postinDoc in listOPosts:
   6:          trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
   7:      p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
   8:      testEntry = ['love', 'my', 'dalmation']
   9:      thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
  10:      print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)
  11:      testEntry = ['stupid', 'garbage']
  12:      thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
  13:      print testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb)

最终结果如下:

   1:  >>> import bayes
   2:  >>> bayes.testingNB()
   3:  ['love', 'my', 'dalmation'] classified as:  0
   4:  ['stupid', 'garbage'] classified as:  1

 

之前我们说过上面只考虑了,这个词是否出现过,没有考虑这个词出现了几次。下面将考虑词出现的次数,代码如下:

   1:  def bagOfWords2VecMN(vocabList, inputSet):
   2:      returnVec = [0]*len(vocabList)
   3:      for word in inputSet:
   4:          if word in vocabList:
   5:              returnVec[vocabList.index(word)] += 1 #这边改成了累加
   6:      return returnVec

示例:使用朴素贝叶斯过滤垃圾邮件

给出过程如下:

机器学习3朴素贝叶斯

切分文本

这边是英文,英文由于单词之间有空格,方便切分,而中文除了句子之间有标点符号外就不好分割了,这样就有了一个新的问题,中文分词问题。这个在以后会介绍,这边根据书先对英文进行分词。

python中有split()方法很容易就切分。

   1:  >>> myStr = 'This book is the best book on Python.'
   2:  >>> myStr.split()
   3:  ['This', 'book', 'is', 'the', 'best', 'book', 'on', 'Python.']

但是最后一个词有标点符号,这个我们通过正则表达式解决,正则表达式在文本分类中是有很大作用的。

   1:  >>> import re
   2:  >>> regEx = re.compile('\\W*')
   3:  >>> listOfTokens = regEx.split(myStr)
   4:  >>> listOfTokens
   5:  ['This', 'book', 'is', 'the', 'best', 'book', 'on', 'Python', '']

机器学习3朴素贝叶斯

之后还有一个空格,我们通过查看字符的长度来解决

   1:  >>> [tok for tok in listOfTokens if len(tok)>0]
   2:  ['This', 'book', 'is', 'the', 'best', 'book', 'on', 'Python']

另外我们考虑构建词库,并不用考虑单词的大小写,全部改为小写

   1:  >>> [tok.lower() for tok in listOfTokens if len(tok)>0]
   2:  ['this', 'book', 'is', 'the', 'best', 'book', 'on', 'python']

文本解析是很大的一个工程,这个正则表达式成书的就好几本了,值得研究还有很多,这边只作简单的解析,复杂的先不予考虑。

比如对于如下文档解析

   1:  >>> emailText = 'http://www.google.com/support/sites/bin/answer.py?hl=en&answer=174623'
   2:  >>> listOfTokens = regEx.split(emailText)
   3:  >>> listOfTokens
   4:  ['http', 'www', 'google', 'com', 'support', 'sites', 'bin', 'answer', 'py', 'hl', 'en', 'answer', '174623']

里面会含有py、en这些不是单词,所有在考虑对于这些的时候,我们处理的时候去掉长度小于3的字符串。

下面给出怎么训练及测试代码

   1:  def textParse(bigString):   
   2:      import re
   3:      listOfTokens = re.split(r'\W*', bigString)
   4:      return [tok.lower() for tok in listOfTokens if len(tok) > 2] 
   5:      
   6:  def spamTest():
   7:      docList=[]; classList = []; fullText =[]
   8:      for i in range(1,26):
   9:          wordList = textParse(open('email/spam/%d.txt' % i).read())
  10:          docList.append(wordList)
  11:          fullText.extend(wordList)
  12:          classList.append(1)
  13:          wordList = textParse(open('email/ham/%d.txt' % i).read())
  14:          docList.append(wordList)
  15:          fullText.extend(wordList)
  16:          classList.append(0)
  17:      vocabList = createVocabList(docList)#创建词汇表
  18:      trainingSet = range(50); testSet=[]           #创建从50个样本集随机取10个作为测试集
  19:      for i in range(10):
  20:          #random.uniform(a, b),用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,一个是下限。
  21:          randIndex = int(random.uniform(0,len(trainingSet)))
  22:          testSet.append(trainingSet[randIndex])
  23:          del(trainingSet[randIndex])  
  24:      trainMat=[]; trainClasses = []
  25:      print('len(trainingSet)',len(trainingSet))#这边是40,要说明一下这个方法
  26:      for docIndex in trainingSet:
  27:          trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
  28:          trainClasses.append(classList[docIndex])
  29:      p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
  30:      errorCount = 0
  31:      for docIndex in testSet:        
  32:          wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
  33:          if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
  34:              errorCount += 1
  35:              print "classification error",docList[docIndex]
  36:      print 'the error rate is: ',float(errorCount)/len(testSet)

 

随机选取一部分作为训练集,剩下的作为测试集,用80%作为训练集,20%作为测试集,这种方法叫留存交叉验证。现在我们只作出一次迭代,为了更精确的估计分类器的错误率,我们应该多次迭代后求出平均错误率。

最后结果如下:

   1:  >>> import bayes
   2:  >>> bayes.spamTest()
   3:  ('len(trainingSet)', 40)
   4:  classification error ['oem', 'adobe', 'microsoft', 'softwares', 'fast', 'order', 'and', 'download', 'microsoft', 'office', 'professional', 'plus', '2007', '2010', '129', 'microsoft', 'windows', 'ultimate', '119', 'adobe', 'photoshop', 'cs5', 'extended', 'adobe', 'acrobat', 'pro', 'extended', 'windows', 'professional', 'thousand', 'more', 'titles']
   5:  the error rate is:  0.1

这边有误判的邮件,如果将垃圾邮件判为正常邮件,这个还好,如果把正常邮件判别为垃圾邮件这个就有问题了,下面我们会给出模型的评估,以及模型的修正,这个再后面会继续介绍。

下面给出另外一个例子。

从个人广告中获取区域倾向

 

前面介绍了过滤网站恶意留言,第二个过滤垃圾邮件,这个例子来发现地域相关的用词

具体流程

机器学习3朴素贝叶斯

这边给出一个题外话,这边要安装feedparser,安装之前用Setuptools 参考https://pypi.python.org/pypi/setuptools#windows windows安装直接下载脚本ez_setup.py

或者直接下载了安装版http://www.lfd.uci.edu/~gohlke/pythonlibs/#setuptools

不过我用的是2.7的它有个bug,这个要修改一下,不然安装报错,具体参考http://bugs.python.org/review/9291/diff/1663/Lib/mimetypes.py

python安装目录lib下的mimetypes.py要修改,修改地方我贴过来

   1:   import sys
   2:   import posixpath
   3:   import urllib
   4:  +from itertools import count
   5:   try:
   6:       import _winreg
   7:   except ImportError:
   8:  @@ -239,19 +240,11 @@
   9:               return
  10:   
  11:           def enum_types(mimedb):
  12:  -            i = 0
  13:  -            while True:
  14:  +            for i in count():
  15:                   try:
  16:  -                    ctype = _winreg.EnumKey(mimedb, i)
  17:  +                    yield _winreg.EnumKey(mimedb, i)
  18:                   except EnvironmentError:
  19:                       break
  20:  -                try:
  21:  -                    ctype = ctype.encode(default_encoding) # omit in 3.x!
  22:  -                except UnicodeEncodeError:
  23:  -                    pass
  24:  -                else:
  25:  -                    yield ctype
  26:  -                i += 1

 

下面我们就可以简单的使用这个feedparser,下面查看一下条目的列表数目

   1:  >>> import feedparser
   2:  >>> ny = feedparser.parse('http://newyork.craigslist.org/stp/index.rss')
   3:  >>> len(ny['entries'])
   4:  100

 

下面写下程序RSS源分类器及高频词去除函数。

在对文本进行解析的时候,我们分析每个词出现的次数,但是有些词出现的很多,但是却没有实际的意思,反而影响权重,比如我们中文中的,的、得等词,英文中的一些简单的代词,谓语动词等等,因此处理的时候要去掉这些高频词汇。

下面处理的时候添加去除前30个高频词的函数

   1:  def calcMostFreq(vocabList,fullText):
   2:      import operator
   3:      freqDict = {}
   4:      for token in vocabList:#遍历词汇表
   5:          freqDict[token]=fullText.count(token)#统计token出现的次数 构成词典
   6:      sortedFreq = sorted(freqDict.iteritems(), key=operator.itemgetter(1), reverse=True) 
   7:      return sortedFreq[:30]       
   8:   
   9:  #这个跟spamTest()基本上一样,不同在于这边访问的是RSS源,最后返回词汇表,以及不同分类每个词出现的概率
  10:  def localWords(feed1,feed0):#使用两个RSS源作为参数
  11:      import feedparser
  12:      docList=[]; classList = []; fullText =[]
  13:      minLen = min(len(feed1['entries']),len(feed0['entries']))
  14:      for i in range(minLen):
  15:          wordList = textParse(feed1['entries'][i]['summary'])
  16:          docList.append(wordList)
  17:          fullText.extend(wordList)
  18:          classList.append(1) 
  19:          wordList = textParse(feed0['entries'][i]['summary'])
  20:          docList.append(wordList)
  21:          fullText.extend(wordList)
  22:          classList.append(0)
  23:      vocabList = createVocabList(docList)#创建词汇表
  24:      top30Words = calcMostFreq(vocabList,fullText)   #去掉top30的词
  25:      for pairW in top30Words:
  26:          if pairW[0] in vocabList: vocabList.remove(pairW[0])
  27:      trainingSet = range(2*minLen); testSet=[]           #创建测试集
  28:      for i in range(20):
  29:          randIndex = int(random.uniform(0,len(trainingSet)))
  30:          testSet.append(trainingSet[randIndex])
  31:          del(trainingSet[randIndex])  
  32:      trainMat=[]; trainClasses = []
  33:      for docIndex in trainingSet:
  34:          trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
  35:          trainClasses.append(classList[docIndex])
  36:      p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
  37:      errorCount = 0
  38:      for docIndex in testSet:        
  39:          wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
  40:          if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
  41:              errorCount += 1
  42:      print 'the error rate is: ',float(errorCount)/len(testSet)
  43:      return vocabList,p0V,p1V

运行结果

   1:  >>> import bayes
   2:  >>> import feedparser
   3:  >>> ny = feedparser.parse('http://newyork.craigslist.org/stp/index.rss')
   4:  >>> sf = feedparser.parse('http://sfbay.craigslist.org/stp/index.rss')
   5:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
   6:  the error rate is:  0.45
   7:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
   8:  the error rate is:  0.4
   9:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
  10:  the error rate is:  0.45
  11:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
  12:  the error rate is:  0.25
  13:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
  14:  the error rate is:  0.3
  15:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
  16:  the error rate is:  0.4
  17:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
  18:  the error rate is:  0.35
  19:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
  20:  the error rate is:  0.5
  21:  >>> vocabList,pSF,pNY = bayes.localWords(ny,sf)
  22:  the error rate is:  0.45

为了得到错误率的精确估计,我们对上述实验进行多次,后取平均值。

另外这个错误率挺高的,不过我们现在关心的是单词的概率,我们可以改变上面去掉30个词,我们可以去掉前100,另外我们可以通过整理的停用词表,就是用于句子结构的辅助词表,这样最后的错误率会有一定的改观。

最后我们分析一下数据,显示地域相关的用词,也就是计算在这个分类下出现概率最大的词。

   1:  def getTopWords(ny,sf):
   2:      import operator
   3:      vocabList,p0V,p1V=localWords(ny,sf)
   4:      topNY=[]; topSF=[]
   5:      for i in range(len(p0V)):
   6:          if p0V[i] > -5.4 : topSF.append((vocabList[i],p0V[i]))
   7:          if p1V[i] > -5.4 : topNY.append((vocabList[i],p1V[i]))
   8:      sortedSF = sorted(topSF, key=lambda pair: pair[1], reverse=True)
   9:      print "SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**"
  10:      for item in sortedSF:
  11:          print item[0]
  12:      sortedNY = sorted(topNY, key=lambda pair: pair[1], reverse=True)
  13:      print "NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**"
  14:      for item in sortedNY:
  15:          print item[0]

结果如下:

   1:  >>> import bayes
   2:  >>> import feedparser
   3:  >>> ny = feedparser.parse('http://newyork.craigslist.org/stp/index.rss')
   4:  >>> sf = feedparser.parse('http://sfbay.craigslist.org/stp/index.rss')
   5:  >>> bayes.getTopWords(ny,sf)
   6:  the error rate is:  0.4
   7:  SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**
   8:  watch
   9:  true
  10:  let
  11:  found
  12:  play
  13:  chill
  14:  should
  15:  live
  16:  where
  17:  other
  18:  NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**
  19:  minded
  20:  did
  21:  women
  22:  nyc
  23:  home
  24:  feel
  25:  few
  26:  non
  27:  platonic
  28:  average
  29:  problem

那这样这朴素贝叶斯的使用基本完成,虽然我们假设属性值相互独立不准确,不过有研究表明,在有些领域该算法完全可以跟决策树,神经网络这样算法媲美。

如果独立假设可以满足的话,则该分类算法和其他分类算法相比的话,目前有最高的准确率跟效率。

对于贝叶斯方法,下面可以研究的贝叶斯网络方法,这个在后续工作中会继续学习。