一、朴素贝叶斯算法介绍
1、朴素贝叶斯算法概述
朴素贝叶斯算法是一种经典的概率分类算法,它基于贝叶斯定理和特征独立性假设。该算法常被用于文本分类、垃圾邮件过滤、情感分析等领域。
朴素贝叶斯算法的核心思想是通过已知类别的训练样本集,学习出每个类别的概率分布模型,然后根据待分类样本的特征,利用贝叶斯定理计算出样本属于各个类别的后验概率,最终选择具有最大后验概率的类别作为分类结果。
在朴素贝叶斯算法中,特征之间被假设为相互独立,这是为了简化计算。尽管这个假设在现实问题中并不总是成立,但朴素贝叶斯算法仍然表现出良好的分类效果。
2、贝叶斯公式
贝叶斯公式(Bayes' theorem)是概率论中的重要定理,用于计算在给定某一事件发生的条件下,另一事件发生的概率。用数学语言表达就是:支持某项属性的事件发生得愈多,则该属性成立的可能性就愈大。该公式的数学表达如下所示:
其中:
- ( P(A|B) ) 表示在事件 B 发生的条件下事件 A 发生的概率,称为后验概率(posterior probability)。
- ( P(B|A) ) 表示在事件 A 发生的条件下事件 B 发生的概率,称为似然度(likelihood)。
- ( P(A) ) 和 ( P(B) ) 分别表示事件 A 和事件 B 单独发生的概率,分别称为先验概率(prior probability)。
先验概率:即基于统计的概率,是基于以往历史经验和分析得到的结果,不需要依赖当前发生的条件。
后验概率:则是从条件概率而来,由因推果,是基于当下发生了事件之后计算的概率,依赖于当前发生的条件。
条件概率:记事件A发生的概率为P(A),事件B发生的概率为P(B),则在B事件发生的前提下,A事件发生的概率即为条件概率,记为P(A|B),读作“在B条件下A的概率”。
联合概率:表示两个事件共同发生的概率。A与B的联合概率表示为P(AB),或者P(A,B),或者P(A∩B)。
3、朴素贝叶斯算法的原理
朴素贝叶斯分类器是一类简单的概率分类器,在强(朴素)独立性假设的条件下运用贝叶斯公式来计算每个类别的后验概率,假设每个特征之间没有联系。
通俗的解释:已知结果(先验概率),结果与在此结果为条件下出现的现象(条件概率)相乘的到结果和现象同时发生的联合概率。除以现象单独发生的概率,就得出在某现象发生的条件下,发生结果的概率(后验概率)
它的原理可以简单概括如下:
-
贝叶斯定理: 贝叶斯定理描述了在已知一些条件下计算另一条件概率的关系。对于分类问题,它表示了在观察到特征值 (x) 的情况下,某个类别 (c) 的概率,即 (P(c|x))。
-
特征条件独立假设: 朴素贝叶斯分类器假设给定类别的情况下,各个特征之间是相互独立的,也就是说特征之间不存在关联性。这个假设使得分类器的计算变得简单,并且易于实现。
-
分类决策规则: 根据贝叶斯定理和特征条件独立假设,可以计算样本属于每个类别的后验概率 (P(c|x)),然后选择具有最大后验概率的类别作为样本的分类结果。
-
参数估计: 在实际应用中,需要通过训练数据集来估计先验概率 (P(c)) 和条件概率 (P(x|c))。常见的估计方法包括最大似然估计和拉普拉斯平滑等。
二、朴素贝叶斯算法实现垃圾邮件分类
1、实现步骤
(1)、收集数据:提供文本文件
(2)、准备数据:将文本文件解析成词条向量
(3)、分析数据:检查词条确保解析的正确性
(4)、训练算法:使用之前建立的trainNB0()函数
(5)、测试算法:使用classifyNB(),并且构建一个新的测试函数来计算文档集的错误率
(6)、使用算法:构建一个完整的程序对一组文档进行分类,并显示错误率
2、代码实现
准备数据
垃圾邮件和正常邮件都有各25个,它们都是以文本文件txt的格式存储
、
图2-1
图2-3
图2-3就是一份垃圾邮件的示例
文本切分
拿到一份很长的数据文本之后,我们需要对其进行切分,提取到各个单词,我们可以通过下面代码的方式来实现:
mySent='This book is the best book on python or M.L. I have ever laid eyes upon.'
print(mySent.split())
import re
mySent='This book is the best book on python or M.L. I have ever laid eyes upon.'
regEX=re.compile('\\W+')
listOfTokens=regEX.split(mySent)
print(listOfTokens)
import re
mySent='This book is the best book on python or M.L. I have ever laid eyes upon.'
regEX=re.compile('\\W+')
listOfTokens=regEX.split(mySent)
print([tok for tok in listOfTokens if len(tok)>0])
print([tok.lower() for tok in listOfTokens if len(tok)>0])
代码的运行结果如下图所示:
图2-3
可以发现通过正则表达式来进行切分并且将字符串全部转换成小写,去掉标点符号可以很好的将一串长文本切分成各个小单词
def textParse(bigString):
import re
listOfTokens = re.split(r'\W*', bigString)
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
textParse(bigString)
函数用于将文本进行分词处理,并转换为小写形式。
文本文件解析
我们不仅仅要将字符串拆分成各个单词,我们还要讲各个句子转换成向量
def createVocabList(dataSet):
vocabSet=set()
for document in dataSet:
vocabSet=vocabSet|set(document) #两个集合的并集
return list(vocabSet)
def setOfWords2Vec(vocabList,inputSet):
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 vocabulary!"%word)
return returnVec
createVocabList(dataSet)
函数通过遍历数据集,创建一个不重复词汇的列表。
setOfWords2Vec(vocabList, inputSet)
函数将文本转换为词向量表示形式,其中向量的每个元素表示对应词汇在文本中是否出现。
训练算法
def trainNB0(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix)
numWords=len(trainMatrix[0])
pABusive=sum(trainCategory)/float(numTrainDocs)
# p0Num=np.zeros(numWords)
# p1Num=np.zeros(numWords)
# p0Denom=0.0
# p1Denom=0.0
p0Num=np.ones(numWords)
p1Num=np.ones(numWords)
p0Denom=2.0
p1Denom=2.0
for i in range(numTrainDocs):
if trainCategory[i]==1:
p1Num+=trainMatrix[i]
p1Denom+=sum(trainMatrix[i])
else:
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
# p1Vect=p1Num/p1Denom
# p0Vect=p0Num/p0Denom
p1Vect=np.log(p1Num/p1Denom)
p0Vect=np.log(p0Num/p0Denom)
return p0Vect,p1Vect,pABusive
trainNB0(trainMatrix, trainCategory)
函数通过朴素贝叶斯算法计算侮辱性文字和正常言论的条件概率,并得到类别标签的先验概率。
贝叶斯分类
#贝叶斯分类函数
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1=sum(vec2Classify*p1Vec)+np.log(pClass1)
p0=sum(vec2Classify*p0Vec)+np.log(1-pClass1)
if p1>p0:
return 1
else:
return 0
classifyNB(vec2Classify, p0Vec, p1Vec, pClass1)
函数根据贝叶斯分类规则,计算输入文本属于侮辱性文字和正常言论的概率,并返回分类结果。
垃圾邮件分类器的实现
def spamTest():
docList = []
classList = []
fullText = []
for i in range(1, 26): # 遍历25个txt文件
wordList = textParse(open('D:/实验报告/机器学习/朴素贝叶斯/email/spam/%d.txt' % i,'r',encoding='latin1').read()) # 读取每个垃圾邮件,并字符串转换成字符串列表
docList.append(wordList)
fullText.append(wordList)
classList.append(1) # 标记垃圾邮件,1表示垃圾文件
wordList = textParse(open('D:/实验报告/机器学习/朴素贝叶斯/email/ham/%d.txt' % i,'r',encoding='latin1').read()) # 读取每个非垃圾邮件,并字符串转换成字符串列表
docList.append(wordList)
fullText.append(wordList)
classList.append(0) # 标记正常邮件,0表示正常文件
vocabList = createVocabList(docList) # 创建词汇表,不重复
trainingSet = list(range(50))
testSet = [] # 创建存储训练集的索引值的列表和测试集的索引值的列表
for i in range(10): # 从50个邮件中,随机挑选出40个作为训练集,10个做测试集
randIndex = int(random.uniform(0, len(trainingSet))) # 随机选取索索引值
testSet.append(trainingSet[randIndex]) # 添加测试集的索引值
del (trainingSet[randIndex]) # 在训练集列表中删除添加到测试集的索引值
trainMat = []
trainClasses = [] # 创建训练集矩阵和训练集类别标签系向量
for docIndex in trainingSet: # 遍历训练集
trainMat.append(setOfWords2Vec(vocabList, docList[docIndex])) # 将生成的词集模型添加到训练矩阵中
trainClasses.append(classList[docIndex]) # 将类别添加到训练集类别标签系向量中
p0V, p1V, pSpam = trainNB0(np.array(trainMat), np.array(trainClasses)) # 训练朴素贝叶斯模型
errorCount = 0 # 错误分类计数
for docIndex in testSet: # 遍历测试集
wordVector = setOfWords2Vec(vocabList, docList[docIndex]) # 测试集的词集模型
if classifyNB(np.array(wordVector), p0V, p1V, pSpam) != classList[docIndex]: # 如果分类错误
errorCount += 1 # 错误计数加1
# print("分类错误的测试集:",docList[docIndex])
print('错误率:%.2f%%' % (float(errorCount) / len(testSet) * 100))
spamTest()
函数是整个垃圾邮件分类器的主要流程,它读取垃圾邮件和正常邮件数据集,并进行训练集和测试集的划分。然后利用朴素贝叶斯算法进行模型训练,并对测试集进行分类预测,最终输出分类错误率。
实验结果
图2-4
实验分析
当我们运行这段代码进行垃圾邮件分类实验时,会得到一个错误率的输出结果。这个错误率代表了分类器在测试集上的分类准确度,即被错误分类的邮件所占的比例。
通过观察错误率,我们可以对实验结果进行一些分析:
-
如果错误率很低(接近0%),意味着分类器在识别垃圾邮件方面表现出色,具有较高的准确性。这是一个理想的结果,说明分类器能够有效地区分垃圾邮件和正常邮件。
-
如果错误率较高(超过10%或更高),则意味着分类器在垃圾邮件分类方面表现较差,准确性较低。这可能是由于数据集的特点或者分类算法的选择问题导致的。需要进一步考虑改进算法、调整参数或使用更复杂的特征工程方法来提高分类器的性能。
此外,还可以对分类错误的样本进行分析,了解分类器的误判情况。例如,查看被错误分类为垃圾邮件的正常邮件,或者被错误分类为正常邮件的垃圾邮件。这可以帮助我们发现分类器的弱点,并进一步优化算法。
需要注意的是,这段代码只是一个简单的垃圾邮件分类器的示例,实际应用中可能需要更复杂的特征工程、模型选择和调优等步骤来提高分类器的性能。
3、实验小结
-
特征处理的重要性:对文本数据进行适当的预处理和特征提取是分类任务中的重要一环。在这个实验中,我们将文本转化为词向量表示,利用词汇出现的频率作为特征,从而实现邮件的分类。
-
朴素贝叶斯分类器的应用:朴素贝叶斯算法是一种简单且有效的分类算法,它基于贝叶斯定理和假设特征之间相互独立。在这个实验中,我们使用朴素贝叶斯分类器来对垃圾邮件进行分类,通过计算条件概率和先验概率来得到分类结果。
-
错误率分析的重要性:通过观察错误率,我们可以对分类器的性能进行评估。较低的错误率意味着分类器具有较高的准确性,而较高的错误率则需要进一步改进分类器。此外,还可以对分类错误的样本进行分析,从中发现分类器的弱点,并尝试改进算法或调整参数来提高分类器的性能。