700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 机器学习实战---朴素贝叶斯算法实现+使用K折交叉验证(代码详解+创新)

机器学习实战---朴素贝叶斯算法实现+使用K折交叉验证(代码详解+创新)

时间:2023-12-27 00:37:49

相关推荐

机器学习实战---朴素贝叶斯算法实现+使用K折交叉验证(代码详解+创新)

《机器学习实战朴素贝叶斯算法实现+使用K折交叉验证》

未经允许,不得擅自转载!

提供数据集如下(永久有效,需要的自行下载):

链接:/s/1Sv0ZL3MWqmKDCJEPARibJQ

提取码:v866

另外,完整版学习笔记业已上传,需要的自提!

笔记截图展示(内容详细,多方面解读!):

1.

2.

3.

4.

朴素贝叶斯 工作原理

提取所有文档中的词条并进行去重获取文档的所有类别计算每个类别中的文档数目对每篇训练文档: 对每个类别: 如果词条出现在文档中-->增加该词条的计数值(for循环或者矩阵相加)增加所有词条的计数值(此类别下词条总数)对每个类别: 对每个词条: 将该词条的数目除以总词条数目得到的条件概率(P(词条|类别))返回该文档属于每个类别的条件概率(P(类别|文档的所有词条))

朴素贝叶斯 算法特点

优点: 在数据较少的情况下仍然有效,可以处理多类别问题。缺点: 对于输入数据的准备方式较为敏感。适用数据类型: 标称型数据。

朴素贝叶斯 项目案例

屏蔽社区留言板的侮辱性言论

项目概述

构建一个快速过滤器来屏蔽在线社区留言板上的侮辱性言论。如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标识为内容不当。对此问题建立两个类别:侮辱类和非侮辱类,使用 1 和 0 分别表示。

开发流程

收集数据: 可以使用任何方法

准备数据: 从文本中构建词向量

分析数据: 检查词条确保解析的正确性

训练算法: 从词向量计算概率

测试算法:根据现实情况修改分类器

使用算法: 对社区留言板言论进行分类

要从文本中获取特征,需要先拆分文本。这里的特征是来自文本的词条(token),一个词条是字符的任意组合。可以把词条想象成单词。

以在线社区的留言板为例,为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标识为内容不当。

下面是实战代码。

准备数据: 从文本中构建词向量

我们将把文本看成单词向量或者词条向量,也就是说将句子转换为向量。

考虑出现在所有文档中的所有单词,再决定将哪些词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。

def load_dataset():dataset = [['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']]class_vector = [0, 1, 0, 1, 0, 1] # 1 is abusive, 0 notreturn dataset,class_vector

展示数据集和数据标签为:

数据集为:[['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']]============================================================数据标签为:[0, 1, 0, 1, 0, 1]

接下来需要创建一个包含在所有文档中出现的不重复词的列表,为此使用了Python的set 数据类型。将词条列表输给set 构造函数,set 就会返回一个不重复列表。首先,创建一个空集合,然后将每篇文档返回的新词集合添加到该集合中

def create_vocab_list(dataset):"""创建一个包含所有文档且不出现重复词的列表"""vocab_set = set([]) #create empty setfor document in dataset:vocab_set = vocab_set | set(document) #set()去掉列表中的重复词return list(vocab_set)

我们的结果为:

['cute', 'park', 'quit', 'help', 'stop', 'take', 'dalmation', 'buying', 'not', 'has', 'my', 'I', 'mr', 'how', 'ate', 'please', 'love', 'to', 'stupid', 'so', 'him', 'worthless', 'is', 'posting', 'steak', 'flea', 'problems', 'garbage', 'maybe', 'licks', 'dog', 'food']

获得词汇表后,我们需要使用新的函数,输入参数为词汇表及某个文档,输出的是文档向量,向量的每一元素为1 或者0,分别表示词汇表的单词在输入文档中是否出现。

函数首先创建一个和词汇表等长的向量,并将其元素都设置为0。接着,遍历文档中的所有单词,如果出现了文档中的单词,将其输出的文档向量中的对应值设为1。

#词集模型"""输入为词汇表和文档,检查文档中的单词是否在词汇表中采用词集模型:即对每条文档只记录某个词汇是否存在,而不记录出现的次数创建一个与词汇表长度一致的0向量,在当前样本中出现的词汇标记为1将一篇文档转换为词向量"""def set_of_words_vector(vocab_list, input_set):return_vector = [0]*len(vocab_list)for word in input_set:if word in vocab_list:return_vector[vocab_list.index(word)] = 1else:print("the word: %s is not in my Vocabulary!" % word)return return_vector

我们看一下函数的运行效果:

[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0]

该函数使用词汇表或者想要检查的所有单词作为输入,然后为其中每一个单词构建一个特征。一旦给定一篇文档,该文档就会被转换为词向量。

训练算法: 从词向量计算概率

我们实现朴素贝叶斯分类器训练函数:

"""朴素贝叶斯分类器训练函数"""def train_native_bayes(train_matrix,train_category):num_train_docs=len(train_matrix)num_words=len(train_matrix[0])p=sum(train_category)/float(num_train_docs)p_0_num=zeros(num_words)p_1_num=zeros(num_words)p_0_denom=0.0p_1_denom=0.0for i in range(num_train_docs):if train_category[i]==1:p_1_num+=train_matrix[i]p_1_denom+=sum(train_matrix[i])else:p_0_num+=train_matrix[i]p_0_denom+=sum(train_matrix[i])p_1_vector=(p_1_num/p_1_denom)p_0_vector=(p_0_num/p_0_denom)return p_0_vector,p_1_vector,p

代码函数中的输入参数为文档矩阵train matrix,以及由每篇文档类别标签所构成的向量train category。首先,计算文档属于侮辱性文档(class=1)的概率,即P(1)。

因为这是一个二分类问题,所以可以通过1-P(1)来得到P(0)。

接下来计算P(ωi|c1),P(ωi|c2),需要初始化程序中的分子变量和分母变量。在for循环中,要遍历训练集train matrix 中的所有文档。一旦某个词语(侮辱性或正常词语)在某一文档中出现,则该词对应的个数(P1num) 或者另一类加加1,而且在所有文档中,该文档的总词数也相应加1。对于两个类别都要进行同样的计算处理。最后,对每个元素除以该类别中的总次数即可。

接下来试验一下:

train_mat=[]for i in dataset:train_mat.append(set_of_words_vector(my_vacab_set,i))p_0_vector,p_1_vector,p=train_native_bayes(train_mat,class_vector)print(p)

接下来看这些变量的内部值:

0.5

我们输出一下P(0) 的概率如下:

[0.04166667 0.04166667 0. 0.04166667 0.04166667 0.0. 0.04166667 0.04166667 0. 0. 0.041666670.04166667 0.04166667 0. 0.04166667 0. 0.041666670.04166667 0. 0.04166667 0.04166667 0. 0.041666670. 0.04166667 0.04166667 0. 0.125 0.041666670.04166667 0.08333333]

首先,我们发现文档属于侮辱类的概率p 为0.5,该值是正确的。接下来,看一看在给定文档类别条件下词汇表中单词的出现概率,看看是否正确。词汇表中的第一个词是cute,其在类别0 中出现1 次,而在类别1 中从未出现。对应的条件概率分别为0.041666 67 与0.0。该计算是正确的。

测试算法: 根据现实情况修改分类器

检查这两条曲线,就会发现它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。

我们修改后的分类器为:

"""朴素贝叶斯分类器训练函数"""def train_native_bayes(train_matrix,train_category):num_train_docs=len(train_matrix)num_words=len(train_matrix[0])p=sum(train_category)/float(num_train_docs)p_0_num=ones(num_words)p_1_num=ones(num_words)p_0_denom=2.0p_1_denom=2.0for i in range(num_train_docs):if train_category[i]==1:p_1_num+=train_matrix[i]p_1_denom+=sum(train_matrix[i])else:p_0_num+=train_matrix[i]p_0_denom+=sum(train_matrix[i])p_1_vector=log(p_1_num/p_1_denom)p_0_vector=log(p_0_num/p_0_denom)return p_0_vector,p_1_vector,p

朴素贝叶斯分类函数

def classify_native_bayes(need_to_classify_vector, p_0_vector, p_1_vector, p_class):p_1 = sum(need_to_classify_vector * p_1_vector) + log(p_class) #element-wise multp_0 = sum(need_to_classify_vector * p_0_vector) + log(1.0 - p_class)if p_1 > p_0:return 1else:return 0

要分类的向量need to classify vector 以及使用函数train native bayes() 计算得到的三个概率。使用NumPy 的数组来计算两个向量相乘的结果。这里的相乘是指对应元素相乘,即先将两个向量中的第1 个元素相乘,然后将第2 个元素相乘,以此类推。接下来将词汇表中所有词的对应值相加,然后将该值加到类别的对数概率上。最后,比较类别的概率返回大概率对应的类别标签。

def testing_native_bayes():dataset,class_vector=load_dataset()my_vacab_set = create_vocab_list(dataset)my_vacab_set.sort()train_mat=[]for i in dataset:train_mat.append(set_of_words_vector(my_vacab_set, i))p_0_vector,p_1_vector,p = train_native_bayes(array(train_mat),array(class_vector))test_entry = ['love','my']this_doc = array(set_of_words_vector(my_vacab_set, test_entry))print(test_entry,'classified as: ',classify_native_bayes(this_doc,p_0_vector,p_1_vector,p))test_entry_1 = ['stupid','garbage']this_doc_1 = array(set_of_words_vector(my_vacab_set, test_entry_1))print(test_entry_1,'classified as: ',classify_native_bayes(this_doc_1,p_0_vector,p_1_vector,p))

下面来看看实际结果:

['love', 'my'] classified as: 0['stupid', 'garbage'] classified as: 1

准备数据:文档词袋模型

目前为止,我们将每个词的出现与否作为一个特征,这可以被描述为词集模型(setof-words model)。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为词袋模型(bag-of-words model)。

在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为适应词袋模型,需要对函数set of words vector() 稍加修改,修改后的函数称为bag of words vector()。

下面的程序给出了基于词袋模型的朴素贝叶斯代码。它与函数set of words vector()几乎完全相同,唯一不同的是每当遇到一个单词时,它会增加词向量中的对应值,而不只是将对应的数值设为1。

"""朴素贝叶斯词袋模型如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现中文档中所不能表达的某种信息"""def bag_word_vector(vocab_list,input_set):return_vector=[0]*len(vocab_list)for word in input_set:if word in vocab_list:return_vector[vocab_list.index(word)]+=1return return_vector

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

在前面那个简单的例子中,我们引入了字符串列表。使用朴素贝叶斯解决一些现实生活中的问题时,需要先从文本内容得到字符串列表,然后生成词向量。

下面这个例子中,我们将了解朴素贝叶斯的一个最著名的应用:电子邮件垃圾过滤。

准备数据:切分文本

前一节中的词向量是预先给定的,下面介绍如何从文本文档中构建自己的词列表。

对于一个文本字符串,可以使用Python 的string.split() 方法将其切分。但是标点符号也被当成了词的一部分。

我们可以使用正则表示式来切分句子,其中分隔符是除单词、数字外的任意字符串。

但是里面的空字符串需要去掉。可以计算每个字符串的长度,只返回长度大于0 的字符串。

我们的Python 代码实现如下:

"""函数说明:接收一个大字符串并将其解析为字符串列表"""def text_parse(big_string):# 将字符串转换为字符列表list_of_tokens = re.split(r"[0-9!@#$%^&*()?\n~]",big_string) # 将特殊符号作为切分标志进行字符串切分,即非字母、非数字return [tok.lower() for tok in list_of_tokens if len(tok) > 2] # 除了单个字母,例如大写的I,其它单词变成小写

2.测试算法:使用朴素贝叶斯进行交叉验证

现在来看数据集中一封完整的电子邮件的实际处理结果。该数据集放在email 文件夹中,该文件夹又包含两个子文件夹,分别是spam 与ham。

我们的分类函数如下:

"""函数说明:测试朴素贝叶斯分类器,使用朴素贝叶斯进行交叉验证"""def spam_test():doc_list=[]class_vector=[]full_text=[]for i in range(1,26): # 遍历25个txt文件word_list=text_parse(open('native_bayes email dataset/spam/%d.txt'%i,'r').read()) # 读取每个垃圾邮件,并字符串转换成字符串列表doc_list.append(word_list)full_text.extend(word_list)class_vector.append(1) # 标记垃圾邮件,1表示垃圾文件word_list=text_parse(open('native_bayes email dataset/ham/%d.txt'%i,'r').read()) # 读取每个非垃圾邮件,并字符串转换成字符串列表doc_list.append(word_list)full_text.extend(word_list)class_vector.append(0) # 标记正常邮件,0表示正常文件vocab_list=create_vocab_list(doc_list) # 创建词汇表,不重复training_set=list(range(50))test_set=[] # 创建存储训练集的索引值的列表和测试集的索引值的列表for i in range(0,10): # 从50个邮件中,随机挑选出40个作为训练集,10个做测试集rand_index=int(random.uniform(0,len(training_set))) # 随机选取索索引值test_set.append(training_set[rand_index]) # 添加测试集的索引值del (training_set[rand_index]) # 在训练集列表中删除添加到测试集的索引值train_mat=[]train_class=[] # 创建训练集矩阵和训练集类别标签系向量for doc_index in training_set: # 遍历训练集train_mat.append(set_of_words_vector(vocab_list,doc_list[doc_index])) # 将生成的词集模型添加到训练矩阵中train_class.append(class_vector[doc_index]) # 将类别添加到训练集类别标签系向量中p_0_vector,p_1_vector,p=train_native_bayes(array(train_mat),array(train_class)) # 训练朴素贝叶斯模型error_count=0 # 错误分类计数for doc_index in test_set: # 遍历测试集word_vector=set_of_words_vector(vocab_list,doc_list[doc_index]) # 测试集的词集模型if classify_native_bayes(array(word_vector),p_0_vector,p_1_vector,p)!=class_vector[doc_index]: # 如果分类错误error_count+=1 # 错误计数加1print('classify error:',doc_list[doc_index])print('the error rate is:',float(error_count)/len(test_set))

导入文件夹spam 与ham 下的文本文件,并将它们解析为词列表。接下来构建一个测试集与一个训练集,两个集合中的邮件都是随机选出的。

本例中共有50 封电子邮件,并不是很多,其中的10 封电子邮件被随机选择为测试集。分类器所需要的概率计算只利用训练集中的文档来完成。Python 变量training set 是一个整数列表,其中的值从0 到49。接下来,随机选择其中10 个文件。选择出的数字所对应的文档被添加到测试集,同时也将其从训练集中剔除。这种随机选择数据的一部分作为训练集,而剩余部分作为测试集的过程称为留存交叉验证(hold-out cross validation)。

我们得到的运行结果如下:

classify error: ['get up to ', ' off at online watchesstore', 'discount watches for all famous brands', ' watches: arolexbvlgari, dior, hermes, oris, cartier, ap and more brands', ' louis vuitton bags ', ' wallets', ' gucci bags', ' tiffany ', ' co jewerly', 'enjoy a full ', ' year warranty', 'shipment via reputable courier: fedex, ups, dhl and ems speedpost', 'you will ', ' recieve your order']classify error: ['get up to ', ' off at online watchesstore', 'discount watches for all famous brands', ' watches: arolexbvlgari, dior, hermes, oris, cartier, ap and more brands', ' louis vuitton bags ', ' wallets', ' gucci bags', ' tiffany ', ' co jewerly', 'enjoy a full ', ' year warranty', 'shipment via reputable courier: fedex, ups, dhl and ems speedpost', 'you will ', ' recieve your order', 'save up to ', ' off quality watches']classify error: ['ordercializviagra online ', ' save ', 'nline pharmacy noprescription required', 'buy canadian drugs at wholesale prices and save ', 'fda-approved drugs + superb quality drugs only', 'accept all major credit cards', ' order today', ' from ']the error rate is: 0.3

3.K 折交叉验证

假定现在只完成了一次迭代,那么为了更精确地估计分类器的错误率,就应该进行多次迭代后求出平均错误率。

def one_cross_validate(train_set,train_class,test_set,test_class):#训练模型p_0_vector,p_1_vector,p_c_1 = train_native_bayes(array(train_set),array(train_class))error_count = 0#验证集进行测试for i in range(10):c = classify_native_bayes(array(test_set[i]),p_0_vector,p_1_vector,p_c_1)if c != test_class[i]:error_count += 1return error_count/10def K_Cross_Validate(train_mat,train_class_vector): #K折交叉验证 5rand_index = list(range(50))random.shuffle(rand_index)error_radio = 0.0for i in range(5): #5次index = rand_index #随机索引#选取训练集、验证集索引train_set = []train_cls = []test_set = []test_cls = []test_set_index = set(rand_index[10*i:10*i+10]) # 测试集10train_set_index = set(index)-test_set_index # 验证集#选取训练集、验证集数据for idx in train_set_index:train_set.append(train_mat[idx])train_cls.append(train_class_vector[idx])for idx in test_set_index:test_set.append(train_mat[idx])test_cls.append(train_class_vector[idx])print('第%d个子集的误差率为:'%(i+1),one_cross_validate(train_set,train_cls,test_set,test_cls))error_radio += one_cross_validate(train_set,train_cls,test_set,test_cls)return error_radio/5

我们最后是求五次的平均误差率。

我们导入需要的数据集并输出最终的结果为:

def create_dataset():data_set_list=[] #全部数据集class_vector = [] #标签值#获取数据spam_path = "native_bayes email dataset/spam/{}.txt" #获取文件路径ham_path = "native_bayes email dataset/ham/{}.txt"for i in range(1, 26): # 两个路径各有25个文件document_data_1 = open(spam_path.format(i), 'r').read()# 使用正则进行分割,除了空格、还有标点都可以用于分割word_vector = text_parse(document_data_1) # \W*表示匹配多个非字母、数字、下划线的字符data_set_list.append([item for item in word_vector if len(item) > 0])class_vector.append(1)document_data_2 = open(ham_path.format(i), 'r').read()# 使用正则进行分割,除了空格、还有标点都可以用于分割word_vector_2 = text_parse(document_data_2) # \W*表示匹配多个非字母、数字、下划线的字符data_set_list.append([item for item in word_vector_2 if len(item) > 0])class_vector.append(0)return data_set_list, class_vector

运行结果如下:

第1个子集的误差率为: 0.2第2个子集的误差率为: 0.4第3个子集的误差率为: 0.2第4个子集的误差率为: 0.2第5个子集的误差率为: 0.45折交叉验证的错误率为:0.27999999999999997

需要注意的是,因为我们对数据集的划分是随机的,所以每次运行的结果会不相同。

完整代码

from numpy import *import redef load_dataset():dataset = [['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']]class_vector = [0, 1, 0, 1, 0, 1] # 1 is abusive, 0 notreturn dataset,class_vectordataset,class_vector=load_dataset()print('数据集为:\n',dataset)print('=='*30)print('数据标签为:\n',class_vector)print('=='*30)def create_vocab_list(dataset):"""创建一个包含所有文档且不出现重复词的列表"""vocab_set = set([]) #create empty setfor document in dataset:vocab_set = vocab_set | set(document) #set()去掉列表中的重复词return list(vocab_set)my_vacab_set=create_vocab_list(dataset)print(my_vacab_set)#词集模型"""输入为词汇表和文档,检查文档中的单词是否在词汇表中采用词集模型:即对每条文档只记录某个词汇是否存在,而不记录出现的次数创建一个与词汇表长度一致的0向量,在当前样本中出现的词汇标记为1将一篇文档转换为词向量"""def set_of_words_vector(vocab_list, input_set):return_vector = [0]*len(vocab_list)for word in input_set:if word in vocab_list:return_vector[vocab_list.index(word)] = 1else:print("the word: %s is not in my Vocabulary!" % word)return return_vectorprint(set_of_words_vector(my_vacab_set,dataset[0]))"""朴素贝叶斯词袋模型如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现中文档中所不能表达的某种信息"""def bag_word_vector(vocab_list,input_set):return_vector=[0]*len(vocab_list)for word in input_set:if word in vocab_list:return_vector[vocab_list.index(word)]+=1return return_vectorprint(bag_word_vector(my_vacab_set,dataset[0]))"""朴素贝叶斯分类器训练函数"""def train_native_bayes(train_matrix,train_category):num_train_docs=len(train_matrix)num_words=len(train_matrix[0])p=sum(train_category)/float(num_train_docs)p_0_num=ones(num_words)p_1_num=ones(num_words)p_0_denom=2.0p_1_denom=2.0for i in range(num_train_docs):if train_category[i]==1:p_1_num+=train_matrix[i]p_1_denom+=sum(train_matrix[i])else:p_0_num+=train_matrix[i]p_0_denom+=sum(train_matrix[i])p_1_vector=log(p_1_num/p_1_denom)p_0_vector=log(p_0_num/p_0_denom)return p_0_vector,p_1_vector,ptrain_mat=[]for i in dataset:train_mat.append(set_of_words_vector(my_vacab_set,i))p_0_vector,p_1_vector,p=train_native_bayes(train_mat,class_vector)print(p)print(p_0_vector)def classify_native_bayes(need_to_classify_vector, p_0_vector, p_1_vector, p_class):p_1 = sum(need_to_classify_vector * p_1_vector) + log(p_class) #element-wise multp_0 = sum(need_to_classify_vector * p_0_vector) + log(1.0 - p_class)if p_1 > p_0:return 1else:return 0def testing_native_bayes():dataset,class_vector=load_dataset()my_vacab_set = create_vocab_list(dataset)my_vacab_set.sort()train_mat=[]for i in dataset:train_mat.append(set_of_words_vector(my_vacab_set, i))p_0_vector,p_1_vector,p = train_native_bayes(array(train_mat),array(class_vector))test_entry = ['love','my']this_doc = array(set_of_words_vector(my_vacab_set, test_entry))print(test_entry,'classified as: ',classify_native_bayes(this_doc,p_0_vector,p_1_vector,p))test_entry_1 = ['stupid','garbage']this_doc_1 = array(set_of_words_vector(my_vacab_set, test_entry_1))print(test_entry_1,'classified as: ',classify_native_bayes(this_doc_1,p_0_vector,p_1_vector,p))print(testing_native_bayes())"""函数说明:接收一个大字符串并将其解析为字符串列表"""def text_parse(big_string):# 将字符串转换为字符列表list_of_tokens = re.split(r"[0-9!@#$%^&*()?\n~]",big_string) # 将特殊符号作为切分标志进行字符串切分,即非字母、非数字return [tok.lower() for tok in list_of_tokens if len(tok) > 2] # 除了单个字母,例如大写的I,其它单词变成小写"""函数说明:测试朴素贝叶斯分类器,使用朴素贝叶斯进行交叉验证"""def spam_test():doc_list=[]class_vector=[]full_text=[]for i in range(1,26): # 遍历25个txt文件word_list=text_parse(open('native_bayes email dataset/spam/%d.txt'%i,'r').read()) # 读取每个垃圾邮件,并字符串转换成字符串列表doc_list.append(word_list)full_text.extend(word_list)class_vector.append(1) # 标记垃圾邮件,1表示垃圾文件word_list=text_parse(open('native_bayes email dataset/ham/%d.txt'%i,'r').read()) # 读取每个非垃圾邮件,并字符串转换成字符串列表doc_list.append(word_list)full_text.extend(word_list)class_vector.append(0) # 标记正常邮件,0表示正常文件vocab_list=create_vocab_list(doc_list) # 创建词汇表,不重复training_set=list(range(50))test_set=[] # 创建存储训练集的索引值的列表和测试集的索引值的列表for i in range(0,10): # 从50个邮件中,随机挑选出40个作为训练集,10个做测试集rand_index=int(random.uniform(0,len(training_set))) # 随机选取索索引值test_set.append(training_set[rand_index]) # 添加测试集的索引值del (training_set[rand_index]) # 在训练集列表中删除添加到测试集的索引值train_mat=[]train_class=[] # 创建训练集矩阵和训练集类别标签系向量for doc_index in training_set: # 遍历训练集train_mat.append(set_of_words_vector(vocab_list,doc_list[doc_index])) # 将生成的词集模型添加到训练矩阵中train_class.append(class_vector[doc_index]) # 将类别添加到训练集类别标签系向量中p_0_vector,p_1_vector,p=train_native_bayes(array(train_mat),array(train_class)) # 训练朴素贝叶斯模型error_count=0 # 错误分类计数for doc_index in test_set: # 遍历测试集word_vector=set_of_words_vector(vocab_list,doc_list[doc_index]) # 测试集的词集模型if classify_native_bayes(array(word_vector),p_0_vector,p_1_vector,p)!=class_vector[doc_index]: # 如果分类错误error_count+=1 # 错误计数加1print('classify error:',doc_list[doc_index])print('the error rate is:',float(error_count)/len(test_set))spam_test()def one_cross_validate(train_set,train_class,test_set,test_class):#训练模型p_0_vector,p_1_vector,p_c_1 = train_native_bayes(array(train_set),array(train_class))error_count = 0#验证集进行测试for i in range(10):c = classify_native_bayes(array(test_set[i]),p_0_vector,p_1_vector,p_c_1)if c != test_class[i]:error_count += 1return error_count/10def K_Cross_Validate(train_mat,train_class_vector): #K折交叉验证 5rand_index = list(range(50))random.shuffle(rand_index)error_radio = 0.0for i in range(5): #5次index = rand_index #随机索引#选取训练集、验证集索引train_set = []train_cls = []test_set = []test_cls = []test_set_index = set(rand_index[10*i:10*i+10]) # 测试集10train_set_index = set(index)-test_set_index # 验证集#选取训练集、验证集数据for idx in train_set_index:train_set.append(train_mat[idx])train_cls.append(train_class_vector[idx])for idx in test_set_index:test_set.append(train_mat[idx])test_cls.append(train_class_vector[idx])print('第%d个子集的误差率为:'%(i+1),one_cross_validate(train_set,train_cls,test_set,test_cls))error_radio += one_cross_validate(train_set,train_cls,test_set,test_cls)return error_radio/5def create_dataset():data_set_list=[] #全部数据集class_vector = [] #标签值#获取数据spam_path = "native_bayes email dataset/spam/{}.txt" #获取文件路径ham_path = "native_bayes email dataset/ham/{}.txt"for i in range(1, 26): # 两个路径各有25个文件document_data_1 = open(spam_path.format(i), 'r').read()# 使用正则进行分割,除了空格、还有标点都可以用于分割word_vector = text_parse(document_data_1) # \W*表示匹配多个非字母、数字、下划线的字符data_set_list.append([item for item in word_vector if len(item) > 0])class_vector.append(1)document_data_2 = open(ham_path.format(i), 'r').read()# 使用正则进行分割,除了空格、还有标点都可以用于分割word_vector_2 = text_parse(document_data_2) # \W*表示匹配多个非字母、数字、下划线的字符data_set_list.append([item for item in word_vector_2 if len(item) > 0])class_vector.append(0)return data_set_list, class_vectordata_set_list, class_vector=create_dataset()vocab_list = create_vocab_list(data_set_list)trainMulList = []for doc in data_set_list:trainMulList.append(set_of_words_vector(vocab_list,doc))print('=='*30)print('5折交叉验证的错误率为:\n',K_Cross_Validate(trainMulList,class_vector))

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。