王子子的成长之路

机器学习实战读书笔记 -- 朴素贝叶斯

最近太忙,实在没时间充电了,翻出一篇一年前的学习笔记先顶一下,虽然当今机器学习框架已经封装的非常好了,但是了解何时使用和算法里发生了什么也是很重要的。

简介

用python的文本处理能力将文档切分成词向量,对文档进行分类和过滤,最终将结果转换成人可以理解的信息。
优点:在数据较少的情况下仍然有效,可以处理多类别问题。
缺点:对于输入数据的准备方式较为敏感。
使用数据类型:标称型数据。

流程

朴素贝叶斯的一般流程:
1.收集数据:可以使用任何方法。
2.准备数据:需要数值型或者布尔型数据。
3.分析数据:有大量特征时,绘制特征作用不大,此时使用直方图效果更好。
4.训练算法:计算不同的独立特征的条件概率。
5.测试算法:计算错误率。
6.使用算法:一个常见的朴素贝叶斯应用是文档分类。可以在任意的分类场景中使用朴素贝叶斯分类器。

使用情况分类

决策树和朴素贝叶斯的使用情况分类:
决策树适合标准的离散化数据,并且对数值型数据的处理难以处理。
朴素贝叶斯的要求相对较低。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#-*- encoding:utf-8 -*-
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']]
#1 代表侮辱性文字,0代表正常言论
classVec=[0,1,0,1,0,1]
return postingList,classVec
def createVocabList(dataSet):
# 取唯一值
vocabSet=set([])
for document in dataSet:
vocabSet=vocabSet|set(document)
return list(vocabSet)
def setOfWords2Vec(vocabList,inputSet):
# 参数1唯一值 当前列表参数2原值,出现在当前词组出现在总词库中的索引
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 Vocablary!"%word
return returnVec
def trainNB0(trainMatrix,trainCategory):
#只针对二分类问题
numTrainDocs=len(trainMatrix) # 统计有几个训练用词组文档
numWords=len(trainMatrix[0]) # 词库数量
pAbusive=sum(trainCategory)/float(numTrainDocs) # 侮辱性词组数量和词组数量的比值
p0Num=ones(numWords);p1Num=ones(numWords) #p0Num,p1Num等于总词库数量个1
p0Denom=2.0;p1Denom=2.0
for i in range(numTrainDocs): # 以i遍历每个词组
if trainCategory[i]==1: # 如果是侮辱性词组
p1Num+=trainMatrix[i] # 每个词在总词库副本中的计数+1
p1Denom+=sum(trainMatrix[i]) #侮辱性词组中单词的总数
else:
p0Num+=trainMatrix[i] # 每个词在总词库中的计数+1
p0Denom+=sum(trainMatrix[i]) # 非侮辱性词组中单词的总数
p1Vect=log(p1Num/p1Denom) # 侮辱性词在词库中的占比,避免下溢出,采取自然底数
p0Vect=log(p0Num/p0Denom) # 非侮辱词在词库中的占比
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1=sum(vec2Classify*p1Vec)+log(pClass1) # 出现词组的位置与总字库内词组向量相乘,加自然底数中侮辱性词库在词库中的占比
p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1)
# 权重越大,说明可能性越高
if p1>p0:
return 1
else:
return 0
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)
if __name__=='__main__':
testingNB()

总结

朴素贝叶斯算法是充分的利用概率原理,用概率的方法分类一个对象的所属类别,对多个类型的对象都可以使用。
算法首先收集了所有训练的词组(数字),通过对总体(比如说文章)的的判断训练,让机器清楚每个的词组出现在总体中分类的概率,用对数的方式防止向下溢出,最终整合概率进行分类。