一、关于朴素贝叶斯
朴素贝叶斯(Naive Bayes)是一种基于贝叶斯定理的简单且高效的分类算法。它假设特征之间相互独立,并利用特征条件独立性简化了计算过程,因此称为"朴素"。
朴素贝叶斯分类器是基于概率模型的生成式分类方法。给定一个待分类的样本,朴素贝叶斯分类器通过计算每个类别的后验概率来确定其所属类别。具体而言,朴素贝叶斯将样本的特征向量视为条件独立的事件,并使用贝叶斯定理计算每个类别的概率,然后选择具有最大后验概率的类别作为预测结果。
朴素贝叶斯分类器在文本分类、垃圾邮件过滤、情感分析等领域广泛应用。它具有计算速度快、对小规模数据表现好以及对噪音数据具有一定的鲁棒性等优点。然而,由于朴素贝叶斯算法假设特征之间相互独立,可能无法处理某些复杂的关联关系,导致分类性能有限。
贝叶斯公式的数学表达如下: P(A|B) = (P(B|A) * P(A)) / P(B) 其中,P(A|B)表示在事件B已经发生的条件下事件A发生的概率;P(B|A)表示在事件A已经发生的条件下事件B发生的概率;P(A)和P(B)分别表示事件A和事件B的先验概率(即在没有任何其他信息的情况下,事件A和事件B各自发生的概率)。
二、实现使用朴素贝叶斯垃圾邮件过滤
示例代码:
import re
from numpy import *
# 创建词汇表
def createVocabList(dataSet):
vocabSet = set([]) # 创建一个无序且不重复的集合对象
for document in dataSet:
vocabSet = vocabSet | set(document) # 创建两个集合的并集
return list(vocabSet)
# 朴素贝叶斯词袋模型 setOfWords2Vec 升级版本
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0] * len(vocabList) # 创建一个长度为vocabList的列表returnVec,并将列表中的每个元素都初始化为0
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 = ones(numWords) # 为了防止出现 0 * x 的情况
p1Num = ones(numWords)
p0Denom = 2.0 # 为了防止分母为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 = log(p1Num / p1Denom) # 计算每个词语是侮辱性词汇的概率
p0Vect = log(p0Num / p0Denom) # log是为了防止数据太小导致下溢出
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 textParse(bigString):
regEx = re.compile(r'\W')
listOfTokens = regEx.split(bigString)
var = [tok.lower() for tok in listOfTokens if len(tok) > 2] # 只返回长度大于2的情况
return var
def spamTest():
docList = []
classList = []
fullText = []
# 导入并解析文本文件
for i in range(1, 26): # 因为每个文件夹各有文件25个
wordList = textParse(open('email/spam/%d.txt' % i, encoding="ISO-8859-1").read()) # 读取文件
docList.append(wordList) # 用于存储所有文件的单词列表,二维数组
fullText.extend(wordList) # 这个列表用于存储所有文件的单词,将它们合并成一个大的单词列表
classList.append(1)
wordList = textParse(open('email/ham/%d.txt' % i, encoding="ISO-8859-1").read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList) # 创建不重复的词汇表
trainingSet = list(range(50)) # 训练集的索引,0-49(因为ham和spam各有25个,故一共有50个)
trainingSet = trainingSet
testSet = []
# 随机构造训练集
for i in range(10): # 表示只创建10个测试集、剩下的都是训练集
# 函数生成一个0到len(trainingSet)之间的随机浮点数,然后取整,得到一个随机的索引值randIndex。
randIndex = int(random.uniform(0, len(trainingSet)))
testSet.append(trainingSet[randIndex]) # 将随机选择的索引值randIndex添加到测试集列表testSet中。
trainingSet.pop(randIndex) # 删除训练集中对应的测试集的索引值,以确保不会重复选择作为测试集。
trainMat = []
trainClasses = []
for docIndex in trainingSet:
# 将选中的训练集索引的文本,和词汇表进行对比计算词汇出现的次数
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex]) # 将文档的类别标签添加到trainClasses列表中
# 调用trainNB0函数,传入训练数据的特征向量和类别标签,进行朴素贝叶斯训练,得到分类器的参数
p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))
errorCount = 0 # 计算错误次数,初始值为0
# 对测试集分类
for docIndex in testSet:
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex]) # 计算出现次数
if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]: # 计算结果并判断是否判断正确
errorCount += 1
print("classification error", docList[docIndex])
print('the error rate is: ', float(errorCount) / len(testSet))
if __name__ == '__main__':
spamTest()
部分数据集:
运行结果
三、结论
朴素贝叶斯算法是一种基于贝叶斯定理和特征条件独立性假设的分类算法。它在文本分类、垃圾邮件过滤、情感分析等领域得到了广泛应用。然而,该算法也存在一些优缺点。
优点:
1. 算法简单、易实现:朴素贝叶斯算法基于简单的数学原理,计算速度快,模型构建和训练的时间开销较小。
2. 对小样本数据有效:朴素贝叶斯算法可以通过少量的训练数据就能够估计出模型参数,适用于小样本场景。
3. 鲁棒性强:朴素贝叶斯算法对输入数据的分布假设较弱,对缺失数据和噪声具有一定的鲁棒性。
4. 可处理多类别问题:朴素贝叶斯算法天然支持多分类问题,并且在训练集数据较大时,分类效果较好。
缺点:
1. 特征条件独立性假设:朴素贝叶斯算法假设所有特征之间相互独立,但在实际应用中,很多特征之间可能存在相关性,这可能导致朴素贝叶斯算法的分类性能下降。
2. 需要大量的训练数据:由于朴素贝叶斯算法对数据分布的假设较强,需要足够多的训练数据来保证模型的准确性。
3. 处理连续特征困难:朴素贝叶斯算法通常假设特征是离散的,对于连续特征需要进行离散化处理,这可能引入一定的信息损失。
4. 对输入数据的表达形式较为敏感:朴素贝叶斯算法对输入数据的表达形式较为敏感,对输入数据的表示方式和特征选择有一定要求。