朴素贝叶斯是一种基于贝叶斯定理的分类算法,其核心思想是通过先验概率和样本数据中的条件概率来计算后验概率,进而进行分类预测。算法的"朴素"之处在于假设特征之间是相互独立的,这使得计算变得简单。在分类问题中,朴素贝叶斯通过利用已知信息进行概率推断,选择具有最高后验概率的类别作为预测结果。尽管这是一个较强的假设,但朴素贝叶斯在处理文本分类等问题时表现良好,是一种简单而有效的分类方法。
一、贝叶斯公式
先验概率(Prior Probability):
先验概率是在考虑任何新的观测数据之前,基于以往经验或先前信息对事件发生概率的估计。它是对事件的初始信仰或置信度,没有考虑新的数据。在朴素贝叶斯中,先验概率通常指的是在没有任何新证据的情况下,某一类别的概率。
后验概率(Posterior Probability):
后验概率是在考虑了新的观测数据后,通过贝叶斯定理计算得出的概率。它是基于先验概率和新数据的联合概率,表示在观测到新数据之后对事件发生概率的修正或更新。在朴素贝叶斯中,后验概率是在考虑了特征数据后,某一类别的概率。
贝叶斯定理(Bayes' theorem ):
它是一种通过先验概率和观测数据来更新我们对事件概率的估计的方法。
贝叶斯定理的表达式为:
其中:
- P(A∣B) 是后验概率,表示在观测到B后,A的概率。
- P(B∣A) 是似然度,表示在A条件下观测到B的概率。
- P(A) 是先验概率,表示在考虑任何新的观测数据之前A的概率。
- P(B) 是边缘概率,表示观测到B的概率。
在朴素贝叶斯中,我们通常关注的是在给定某个类别的先验概率(P(A)),以及在该类别下观测到特征数据的似然度(P(B∣A))。通过应用贝叶斯定理,我们可以计算出在考虑特征数据后,该类别的后验概率(P(A∣B)),从而进行分类预测。
二、朴素贝叶斯分类器
朴素贝叶斯分类器是一种基于贝叶斯定理的概率分类算法。其核心思想在于通过先验概率和样本数据中的条件概率,利用贝叶斯定理计算后验概率,从而进行分类预测。"朴素"体现在算法对特征之间的独立性的假设上,使得计算变得简单。在分类问题中,朴素贝叶斯分类器通过比较不同类别的后验概率,选择具有最高概率的类别作为预测结果。尽管基于较强的独立性假设,朴素贝叶斯在文本分类等领域表现出色,是一种简单而有效的分类方法。
基于属性条件独立性假设,我们可以重新表达后验概率P(c∣x)。在这里,d 表示属性的数量,xi 表示在第 i 个属性上的取值。由于对于所有类别来说,P(x) 相同,因此贝叶斯判定准则(即朴素贝叶斯分类器的表达式)为:
显而易见,朴素贝叶斯分类器的训练过程涉及基于训练集 D 估计类先验概率 P(c),并为每个属性估计条件概率 P(xi∣c)。
定义 Dc 表示训练集 D 中第 c 类样本组成的集合。如果有充足的独立同分布样本,我们可以容易地估计类先验概率:
对于离散属性,定义 Dc,xi 表示在第 i 个属性上取值为 xi 的样本组成的集合,条件概率可估计为:
对于连续属性,我们可以考虑概率密度函数,假设 Xi 在第c 类样本上的取值服从高斯分布,其中 μc,i 和 σc,i 分别是第 c 类样本在第i 个属性上取值的均值和方差。
例子:用西瓜数据集训练一个朴素贝叶斯分类器,对测试例进行分类
三、拉普拉斯修正
拉普拉斯修正是朴素贝叶斯分类器中用于处理零概率问题的一种方法。由于属性条件独立性假设,当训练集中某个类别下的某个属性值未出现时,对应的条件概率为零,这可能导致整体概率计算失效。为避免这种情况,拉普拉斯修正通过在频数上添加一个小的常数,确保所有属性值都有非零的概率,从而提高了模型的泛化能力。这种调整有助于更准确地估计先验概率和条件概率,提高了朴素贝叶斯分类器在实际应用中的性能表现。
四、朴素贝叶斯分类器基本步骤
朴素贝叶斯分类器的基本步骤包括以下几个阶段:
-
收集数据: 获取带有标签的训练数据集,其中包含已分类的样本和它们的特征。
-
预处理数据: 对数据进行清理和预处理,包括处理缺失值、标准化数据等。
-
提取特征: 从训练数据中提取用于分类的特征,这些特征应与分类目标相关。
-
训练模型: 使用训练数据集估计类别的先验概率和特征的条件概率,即计算P(c) 和 P(xi∣c)。
-
应用模型: 对于新的未标记数据,使用贝叶斯定理计算后验概率,选择具有最高后验概率的类别作为预测结果。
-
评估模型: 使用测试数据评估模型的性能,通常通过计算分类准确度、精确度、召回率等指标。
五、垃圾邮件过滤
-
创建词汇表:
createVocabList
函数通过遍历数据集中的文档,创建一个包含所有文档中出现的唯一词汇的词汇表。 -
将文本转换为向量:
setOfWords2Vec
函数将文档表示为词集模型,其中向量中的每个元素表示对应词汇在文档中是否出现。bagOfWords2VecMN
函数将文档表示为词袋模型,其中向量中的每个元素表示对应词汇在文档中出现的次数。
-
训练朴素贝叶斯模型:
trainNB0
函数计算类别的先验概率和每个词汇在类别条件下的概率。 -
朴素贝叶斯分类:
classifyNB
函数使用训练好的模型进行分类,返回文档所属的类别。 -
文本解析:
textParse
函数将输入的字符串转换为小写字符列表,并通过正则表达式进行分词。 -
垃圾邮件测试:
spamTest
函数加载垃圾邮件和正常邮件数据集,随机选择训练集和测试集,训练朴素贝叶斯分类器,并计算分类错误率。
# -*- coding: UTF-8 -*-
import numpy as np
import re
import random
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 # 返回文档向量
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0] * len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec # 返回词袋模型
def trainNB0(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix) # 计算训练的文档数目
numWords = len(trainMatrix[0]) # 计算每篇文档的词条数
pAbusive = sum(trainCategory) / float(numTrainDocs) # 文档属于垃圾邮件类的概率
p0Num = np.ones(numWords)
p1Num = np.ones(numWords) # 创建numpy.ones数组,词条出现数初始化为1,拉普拉斯平滑
p0Denom = 2.0
p1Denom = 2.0 # 分母初始化为2 ,拉普拉斯平滑
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 = np.log(p1Num / p1Denom)
p0Vect = np.log(p0Num / p0Denom)
return p0Vect, p1Vect, pAbusive
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + np.log(pClass1)
p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
def textParse(bigString): # 将字符串转换为字符列表
listOfTokens = re.split(r'\W*', bigString) # 将特殊符号作为切分标志进行字符串切分,即非字母、非数字
return [tok.lower() for tok in listOfTokens if len(tok) > 2] # 除了单个字母,例如大写的I,其它单词变成小写
def spamTest():
docList = []
classList = []
fullText = []
for i in range(1, 21):
wordList = textParse(open('email/spam_email/%d.txt' % i, 'r').read())
docList.append(wordList)
fullText.append(wordList)
classList.append(1) # 标记垃圾邮件,1表示垃圾文件
wordList = textParse(open('email/ham_email/%d.txt' % i, 'r').read())
docList.append(wordList)
fullText.append(wordList)
classList.append(0) # 标记正常邮件,0表示正常文件
vocabList = createVocabList(docList)
trainingSet = list(range(40))
testSet = []
for i in range(6): # 从40个邮件中,随机挑选出34个作为训练集,6个做测试集
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('错误率:%.2f%%' % (float(errorCount) / len(testSet) * 100))
if __name__ == '__main__':
spamTest()
六、总结
朴素贝叶斯是一种基于贝叶斯定理的分类算法,通过先验概率和条件概率计算后验概率,实现分类预测。核心思想在于假设特征之间相互独立,使计算简化。学习笔记总结了贝叶斯公式、先验概率、后验概率等基础概念,并深入讨论了朴素贝叶斯分类器的基本步骤,包括数据收集、预处理、特征提取、模型训练、应用和评估。拉普拉斯修正的介绍解决了零概率问题。通过垃圾邮件过滤的例子,学习了将文本转换为向量表示、训练分类器、分类预测和性能评估等实际应用。这份学习笔记奠定了扎实的朴素贝叶斯基础,为理解和应用这一分类算法提供了全面的视角。