使用贝叶斯决策理论,计算两个概率进行分类,属于哪一类别的概率大,就认为属于哪一类。实际计算p(c1|x,y)和p(c2|x, y)。
给定由x,y表示的数据点,p(c1|x,y)和p(c2|x, y)这些数据点来自类别c1,c2的概率是多少。
应用贝叶斯准则
p(ci|x,y)=p(x,y|ci)∗p(ci)p(x,y)p(ci|x,y)=p(x,y|ci)∗p(ci)p(x,y)
以文本分类为例
以w表示一个向量,该向量由文档转换为而成。ci表示距离类别。
p(ci|w⃗ )=p(w⃗ |ci)∗p(ci)p(w⃗ )p(ci|w→)=p(w→|ci)∗p(ci)p(w→)
使用朴素贝叶斯假设,假设各个属性相互独立。即所有词相互独立,该假设又称作条件独立性假设f。其意味着:
p(w⃗ |ci)=p(w0,w1,...wn|ci)=p(w0|ci)∗p(w1|ci)∗...p(wn|ci)p(w→|ci)=p(w0,w1,...wn|ci)=p(w0|ci)∗p(w1|ci)∗...p(wn|ci)
应用上述公式,对每个类计算概率值,然后比较两个概率值的大小,由此判断类别。
- 文档转换为词向量
根据训练集合,构建一个词汇表。根据文档中某个词是否出现在词汇表中,出现设为1,不出现设为0,构建一个词向量,这被称作词集模型(set-of-words model),如果考虑单词出现的次数,出现n次设为n,这种方式称作词袋模型(bag-of-words model) - 构建分类器
把数据分为训练集和测试集。从数据中随机的取出一部分作为测试集,剩下的作为训练集,称作 留存交叉验证(hold-out cross validation)。
根据训练集计算平均每个单词在ci条件下出现的概率:统计训练集单词在ci条件下出现的数目,除以所有总的词汇数目。构建概率向量。 - 测试分类函数
输入词向量,词向量与训练集得到的概率向量相乘,即可得到,该词向量的各个单词出现的概率,根据朴素贝叶斯假设,词向量各个单词出现互相独立,从而计算概率,根据概率大小判断其为哪种类别。
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] #1表示侮辱类,0表示不属于
return postingList,classVec #词条切分后的分档和类别标签
# 创建一个词汇列表,不重复
def create_vocab_list(dataSet):
vocab_set = set()
for i in dataSet:
vocab_set=vocab_set|set(i)
return list(vocab_set)
#词汇表中的词汇,在文档中是否出现。出现设置为1,反之为0;
def words2vec(vocab_set,inputSet):#形参是词汇表和输入文档
return_vec = [0] * len(vocab_set)
for word in inputSet:
if word in vocab_set:
return_vec[vocab_set.index(word)] += 1
else:
print("the word: %s is not in my Vocabulary!" % word)
return return_vec
#朴素贝叶斯分类器训练函数,返回三个变量
#1侮辱类文档条件下,词向量概论p(w|c1);p(w|c2);侮辱类文档概论p(c1)
def train_NBO(trainMatrix,trainCategory):
Number_train_docs = len(trainMatrix)#矩阵的行数
num_words = len(trainMatrix[0]) #矩阵的列数
pabusive = sum(trainCategory)/Number_train_docs
p1 = zeros(num_words);p0=zeros(num_words) #用到除法,故使用numpy函数
# p1 = [0]*num_words;p0=[0]*num_words
# p1Denom=0; p0Denom=0 #初始化分母项
p1Denom = 2 ;p0Denom = 2 #
for i in range(Number_train_docs):
if trainCategory[i]==1:
p1 = p1+trainMatrix[i]
p1Denom = p1Denom + sum(trainMatrix[i])
else :
p0 = p0+trainMatrix[i]
p0Denom = p0Denom +sum(trainMatrix[i])
p1vect = log(p1/p1Denom) #p1vect = p1/p1Denop0vect = p0/p0Denom
p0vect = log(p0/p0Denom)
return p0vect,p1vect,pabusive
def classifyNBO(vec2Classify,p0Vec,p1Vec,pClass1):
#同时,采用自然对数进行处理不会有任何损失。ln(a * b) = ln(a) + ln(b)
p1 = sum(vec2Classify * p1Vec) +log(pClass1)
p0 = sum(vec2Classify * p0Vec) +log(1-pClass1)
if p1>p0:
return 1
else:
return 0
#测试函数
def NBO_Test():
myvocab,classlist = loadDataSet()
myvocab_list = create_vocab_list(myvocab)
num_doc = len(myvocab)
trainMat =[]
for i in myvocab:
trainMat.append(words2vec(myvocab_list,i))
p0V,p1V,pabusive =train_NBO(trainMat,classlist)
testEntry = ['love', 'my', 'dalmation'] # 正面测试文档
thisDoc = array(words2vec(myvocab_list, testEntry)) # 词汇表
classfiy_result = classifyNBO(thisDoc,p0V,p1V,pabusive)
print("['love', 'my', 'dalmation'] is classified as %d" %classfiy_result)
testEntry2 = ['stupid','garbage']
thisDoc = array(words2vec(myvocab_list, testEntry2)) # 词汇表
classfiy_result = classifyNBO(thisDoc, p0V, p1V, pabusive)
print("['stupid','garbage'] is classified as %d" %classfiy_result)
def textParse(String):
import re #引入正则表达式
list_of_tokens = re.split(r'\W+',String)#r表示原生字符串
#注意是 \W,w写。因为\w代表单词数字字符 \W代表非单词的字符,应该以此为分隔符。
return [tok.lower() for tok in list_of_tokens if len(tok)>2 ]
#字符串全部转换成小写 .lower()//.upper()全部转换成大写
# 构建一个新列表的简介方式 [ x for x in list if ...]
def spam_test():
doc_list =[];class_list=[];full_text=[]
for i in range(1,26):#从1开始,上边界不取
# 添加ham邮件
fo = open('F:\pythonProject\MLIAcode\Ch04\email\ham\%d.txt' %i)
string = fo.read()#此处报错,邮件有字符不一致
list = textParse(string)
doc_list.append(list)
full_text.extend(list)
class_list.append(0)
#添加spam邮件
fo = open('F:\pythonProject\MLIAcode\Ch04\email\spam\%d.txt' %i)
string = fo.read()
list = textParse(string)
doc_list.append(list)
full_text.extend(list)
class_list.append(1)
vocab_list = create_vocab_list(doc_list)
#随机拿出10个数据,作为测试集
test_set = []#测试集
#test_class =[]
#training_set = list(range(50)) 训练索引集,转换为列表类。出错,为什么不能强制转化为列表
training_set = [x for x in range(50)]
for i in range(10):
rand_index =int(random.uniform(0,len(training_set)))#不断删除该序列,因此必须不断求长度更新
#print(rand_index)
#print(len(training_set))
test_set.append(training_set[rand_index])
#test_set.append(words2vec(vocab_list,doc_list[i]))
#test_class.append(class_list[rand_index])
del (training_set[rand_index])
#开始训练。剩下的作为训练集合
print(training_set)
train_matrix = [];train_classes=[]
for doc_index in training_set:
train_matrix.append(words2vec(vocab_list,doc_list[doc_index]))
train_classes.append(class_list[doc_index])
p0v,p1v,p_spam =train_NBO(train_matrix,train_classes)
print(p_spam)
#print(len(p0v))
error_count = 0
for doc_index in test_set:
word_vec = words2vec(vocab_list,doc_list[doc_index])
if classifyNBO(word_vec,p0v,p1v,p_spam) != class_list[doc_index]:
#print(test_set[i])
error_count+=1
print('the error rate is %f' %(error_count/len(test_set)))