我有新开了一个专栏,讲解python机器学习的一些实例,本次要学习的是朴素贝叶斯算法的中文邮件分类。
朴素贝叶斯算法的中文邮件分类
1.朴素贝叶斯算法原理
贝叶斯理论:根据一个已发生事件的概率计算另一个事件发生的概率。
朴素:在整个过程中只做最原始,最简单的假设,例如假设特征之间相互独立并且特征同等重要。
简单逻辑:用此算法进行分类时,计算未知样本属于已知类的概率,然后选择概率最大的样本作为分类结果,
简介:朴素贝叶斯分类器发源于古典数学理论,有着坚实的数学基础,以及稳定的分类效率。贝叶斯方法是以贝叶斯理论为基础,使用概率统计的知识对样本数据集进行分类,误判率是很低的。贝叶斯方法的特点是结合先验概率和后验概率,即避免了只使用先验概率的主观偏见,也避免了单独使用样本信息的过拟合现象。在数据集较大的情况下表现出较高的准确率。
朴素贝叶斯方法是在贝叶斯算法的基础上进行了相应的简化,即假定给定目标值时属性之间相互条件独立。属性变量比重差不多,极大地简化了贝叶斯方法的复杂性,但分类效果有所降低。
2.项目简介
项目是利用朴素贝叶斯算法对中文邮件进行分类,邮件有垃圾和非垃圾邮件,统计出现最多的有效词汇,然后统计每个邮件里的有效词汇分别在这个文件里出现的次数,构建特征向量,作为训练集对邮件进行训练,并分类。
3.项目步骤
(1)从电子邮箱中收集足够多的垃圾邮件和非垃圾邮件的内容作为训练集。
(2)读取全部训练集,删除其中的干扰字符,例如【】*。、,等等,然后分词,再删除长度为1的单个字,这样的单个字对于文本分类没有贡献,剩下的词汇认为是有效词汇。
(3)统计全部训练集中每个有效词汇的出现次数,截取出现次数最多的前N(可以根据实际情况进行调整)个。
(4)根据每个经过第2步预处理后的垃圾邮件和非垃圾邮件内容生成特征向量,统计第3步中得到的N个词语分别在该邮件中的出现频率。每个邮件对应于一个特征向量,特征向量长度为N,每个分量的值表示对应的词语在本邮件中出现的次数。例如,特征向量[3, 0, 0, 5]表示第一个词语在本邮件中出现了3次,第二个和第三个词语没有出现,第四个词语出现了5次。
(5)根据第4步中得到特征向量和已知邮件分类创建并训练朴素贝叶斯模型。
(6)读取测试邮件,参考第2步,对邮件文本进行预处理,提取特征向量。
(7)使用第5步中训练好的模型,根据第6步提取的特征向量对邮件进行分类。
4.代码
导入各种库:
from re import sub
from os import listdir
from collections import Counter
from itertools import chain
from numpy import array
from jieba import cut
from sklearn.naive_bayes import MultinomialNB
获取每一封邮件中的所有有效词语:
def getWordsFromFile(txtFile):
# 获取每一封邮件中的所有词语
words = []
# 所有存储邮件文本内容的记事本文件都使用UTF8编码
with open(txtFile, encoding='utf8') as fp:
for line in fp:
# 遍历每一行,删除两端的空白字符
line = line.strip()
# 过滤干扰字符或无效字符
line = sub(r'[.【】0-9、—。,!~*]', '', line)
# 分词
line = cut(line)
# 过滤长度为1的词
line = filter(lambda word: len(word)>1, line)
# 把本行文本预处理得到的词语添加到words列表中
words.extend(line)
# 返回包含当前邮件文本中所有有效词语的列表
return words
训练并保存结果
# 存放所有文件中的单词
# 每个元素是一个子列表,其中存放一个文件中的所有单词
allWords = []
def getTopNWords(topN):
# 按文件编号顺序处理当前文件夹中所有记事本文件
# 训练集中共151封邮件内容,0.txt到126.txt是垃圾邮件内容
# 127.txt到150.txt为正常邮件内容
txtFiles = [str(i)+'.txt' for i in range(151)]
# 获取训练集中所有邮件中的全部单词
for txtFile in txtFiles:
allWords.append(getWordsFromFile(txtFile))
# 获取并返回出现次数最多的前topN个单词
freq = Counter(chain(*allWords))
return [w[0] for w in freq.most_common(topN)]
# 全部训练集中出现次数最多的前600个单词
topWords = getTopNWords(600)
# 获取特征向量,前600个单词的每个单词在每个邮件中出现的频率
vectors = []
for words in allWords:
temp = list(map(lambda x: words.count(x), topWords))
vectors.append(temp)
vectors = array(vectors)
# 训练集中每个邮件的标签,1表示垃圾邮件,0表示正常邮件
labels = array([1]*127 + [0]*24)
# 创建模型,使用已知训练集进行训练
model = MultinomialNB()
model.fit(vectors, labels)
# 下面是保存结果
joblib.dump(model, "垃圾邮件分类器.pkl")
print('保存模型和训练结果成功。')
with open('topWords.txt', 'w', encoding='utf8') as fp:
fp.write(','.join(topWords))
print('保存topWords成功。')
加载并使用训练结果
model = joblib.load("垃圾邮件分类器.pkl")
print('加载模型和训练结果成功。')
with open('topWords.txt', encoding='utf8') as fp:
topWords = fp.read().split(',')
def predict(txtFile):
# 获取指定邮件文件内容,返回分类结果
words = getWordsFromFile(txtFile)
currentVector = array(tuple(map(lambda x: words.count(x),
topWords)))
result = model.predict(currentVector.reshape(1, -1))[0]
return '垃圾邮件' if result==1 else '正常邮件'
# 151.txt至155.txt为测试邮件内容
for mail in ('%d.txt'%i for i in range(151, 156)):
print(mail, predict(mail), sep=':')