- 签证留学 |
- 笔译 |
- 口译
- 求职 |
- 日/韩语 |
- 德语
3. 测试算法:根据现实情况修改分类器
利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算p(w0|1)p(w1|1)p(w2|1)。如果其中一个概率值为0,那么最后的乘积也为0。为降低这种影响,可以将所有词的出现数初始化为1,并将分母初始化为2。
在文本编辑器中打开bayes.py文件,并将trainNB0 () 的第4行和第5行修改为:
poNum = ones (numWords); plNum = ones (numMords)
p0Denom = 2.0; p1Denom ▪ 2.0
另一个遇到的问题是下溢出,这是由于太多很小的数相乘造成的。当计算乘积p(w0|ci)p(w1lci)p(w2|ci)..p(wN|ci)时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。(读者可以用Python尝试相乘许多很小的数,最后四舍五人后会得到0。)一种解决办法是对乘积取自然对数。在代数中有ln(a*b)=ln(a)+ln(b),于是通过求对数可以避免下溢出或者浮点数舍人导致的错误。同时,采用自然对数进行处理不会有任何损失。图1-1给出函数f(x)与ln(f(x))的曲线。检查这两条曲线,就会发现它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。通过修改return前的两行代码,将上述做法用到分类器中:
图1-1函数f(x)与ln(f(x))会一块增大。这表明想求函数的最大值时,可以使用该函数的自然对数来替换原函数进行求解
现在已经准备好构建完整的分类器了。当使用NumPy向量处理功能时,这一切变得十分简单。打开文本编辑器,将下面的代码添加到bayes.py中:
程序清单1-3朴素贝叶斯分类函数
程序清单1-3的代码有4个输入:要分类的向量vec2Classify以及使用函数trainNB0 ()计算得到的三个概率。使用NumPy的数组来计算两个向量相乘的结果①。这里的相乘是指对应元素相乘,即先将两个向量中的第1个元素相乘,然后将第2个元素相乘,以此类推。接下来将词汇表中所有词的对应值相加,然后将该值加到类别的对数概率上。最后,比较类别的概率返回大概率对应的类别标签。这一切不是很难,对吧?
代码的第二个函数是一个便利函数(convenience function),该函数封装所有操作,以节省输入代码的时间。
下面来看看实际结果。将程序清单1-3中的代码添加之后,在Python提示符下输入:
>>> reload(bayes)
>>>bayes.testingNB()
['love', 'my','dalmation'] classified as: 0
['stupid', 'garbage'] classified as: 1
对文本做一些修改,看看分类器会输出什么结果。这个例子非常简单,但是它展示了朴素贝叶斯分类器的工作原理。接下来,我们会对代码做些修改,使分类器工作得更好。
4. 准备数据:文档词袋模型
目前为止,我们将每个词的出现与否作为一个特征,这可以被描述为词集模型(set-of-words model)。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为词袋模型(bag-of-words model)。在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为适应词袋模型,需要对函数setofwords2vec ()稍加修改,修改后的函数称为bagofwords2Vec()。
下面的程序清单给出了基于词袋模型的朴素贝叶斯代码。它与函数setofWords2Vec()几乎完全相同,唯一不同的是每当遇到一个单词时,它会增加词向量中的对应值,而不只是将对应的数值设为1。
程序清单1-4朴素贝叶斯词袋模型
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len (vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
现在分类器已经构建好了,下面我们将利用该分类器来过滤垃圾邮件。
责任编辑:admin