1.贝叶斯公式介绍:
贝叶斯理论指的是,根据一个已发生事件的概率,计算另一个事件的发生概率。贝叶斯理论从数学上的表示可以写成这样:
对于贝叶斯公式我们可以有如下的理解
在使用朴素贝叶斯分类器进行垃圾邮件检测时,一般会将每封邮件表示为一个特征向量,并且使用这些特征向量来训练分类器。常见的朴素贝叶斯分类器包括多项式朴素贝叶斯(Multinomial Naive Bayes)和高斯朴素贝叶斯(Gaussian Naive Bayes)等。
2.代码思路
朴素贝叶斯文本分类代码的整体思路是:
- 数据预处理:
- 获取邮件文本数据,按类别存放
- 对文本进行分割处理,提取词汇
- 构建词汇表
- 模型训练:
- 计算先验概率P(C),即每个类别的概率
- 计算条件概率P(xi|C),即词汇表中每个词在每个类别下的条件概率
- 将P(C)和P(xi|C)作为朴素贝叶斯模型的参数
- 模型测试:
- 对测试集数据也进行词汇提取和向量化
- 计算测试集每个样本属于每个类别的后验概率P(C|x)
- 选择后验概率最大的类别作为分类结果
- 统计分类准确率
- 程序流程:
- 主函数读取数据,进行训练和测试
- 定义了多个函数完成上述具体步骤
3.具体实现
1.导入需要的库:
import os
import re
import numpy as np
from functools import reduce
import random
导入os、re、numpy、functools、random等库,os用于文件操作,re用于正则表达式,numpy用于数值计算,functools中的reduce用于求最大值,random用于随机打乱。
2.定义文本分割函数split_text():
def split_text(text: str):
tokens = re.split(r'\W+', text)
return [tok.lower() for tok in tokens if len(tok) > 2 and not tok.isdigit()]
使用正则表达式切分文本,保留字母词,转换为小写。
3.定义获取训练和测试数据集的函数get_words_data():
def get_words_data():
class_types = [r for r in os.listdir('email') if os.path.isdir(os.path.join('email', r))]
def read_data(filename_: str) -> str:
with open(filename_, 'r', encoding='gbk') as f:
return f.read()
words_data = []
for c in class_types:
for filename in os.listdir(os.path.join('email', c)):
file_data = read_data(os.path.join(f'email/{c}', filename))
words_data.append((c, split_text(file_data)))
return words_data, class_types
读取email文件夹中的数据,按类别存储,读取每个文件并分割得到词列表。
4.定义生成词汇表的函数get_words_label():
def get_words_label(words_data: list) -> list:
words_label = set({})
for words in words_data:
words_label.update(words[1])
res = list(words_label)
res.sort()
return res
从数据集中提取词汇,并排序去重,得到词汇表。
5.定义词向量化的函数get_words_vector():
def get_words_vector(words, words_label: list) -> list:
return [(1 if val == words else 0) if not isinstance(words, list)
else (1 if val in words else 0) for val in words_label]
根据词汇表,将文本转换为词向量。
6.定义朴素贝叶斯训练函数native_bayes_train():
def native_bayes_train(words_label: list, train_data: list, class_types: list, alpha: float = 1e-3):
p_result = {c: np.array([alpha for _ in range(len(words_label))]) for c in class_types}
p_b = {c: alpha for c in class_types}
for data in train_data:
words_vector = np.array(get_words_vector(data[1], words_label))
p_result[data[0]] += words_vector + alpha
p_b[data[0]] += 1 / len(train_data)
for k in p_result:
p_result[k] = np.log(p_result[k])
return p_result, p_b
统计每个分类下每个词的出现次数,计算先验概率和条件概率,得到朴素贝叶斯模型的参数。
7.定义朴素贝叶斯测试函数native_bayes_test():
def native_bayes_test(words_label: list, p_result: dict, test_data: list, p_b: dict, alpha: float = 1e-3) -> float:
accurate = 0
for data in test_data:
words_vector = np.array(get_words_vector(data[1], words_label))
Qs = {key: np.log(p_b[key]) + sum(p_result[key] * words_vector) - np.log(sum(words_vector + alpha)) for key in p_result}
classification = reduce((lambda x, y: x if x[1] > y[1] else y), ((k, Qs[k]) for k in Qs))[0]
accurate += (1 if classification == data[0] else 0) / len(test_data)
return accurate
对测试数据分类,计算后验概率选择最大的作为分类结果,然后计算准确率。
8.主函数main():
def main():
words_data, class_types = get_words_data()
random.shuffle(words_data)
words_label = get_words_label(words_data)
p_result, p_b = native_bayes_train(words_label, words_data[:40], class_types)
accurate = native_bayes_test(words_label, p_result, words_data[40:], p_b)
print(f"DONE! accurate = {(accurate * 100):.2f}%")
if __name__ == '__main__':
main()
调用上面的函数,读取数据,训练模型,测试模型,输出结果。
输出结果:
实验小结:
这次实验验证了朴素贝叶斯算法在文本分类任务上的有效性,通过统计词汇信息,计算不同类别的概率,可以正确分类大部分邮件文档。朴素贝叶斯分类具有训练速度快、分类效率高等优点。通过本次实验,我掌握了朴素贝叶斯文本分类算法的实现方法,并了解了其原理及应用场景。这种基于统计与概率的机器学习方法值得学习和应用到更多文本处理问题中。数据的提取、清洗与特征工程也很重要,需要不断积累处理文本数据的经验。