在机器学习领域,朴素贝叶斯算法是一种常见且强大的分类算法。它被广泛应用于文本分类、垃圾邮件过滤、情感分析等领域。
一、朴素贝叶斯算法
1.先验概率
P(cj)代表还没有训练模型之前,根据历史数据/经验估算cj拥有的初始概率。P(cj)常被称为cj的先验概率 ,它反映了cj的概率分布,该分布独立于样本。通常可以用样例中属于cj的样例数|cj|比上总样例数|D|来近似,即:
2.后验概率
给定数据样本x时cj成立的概率P(cj | x )被称为后验概率,因为它反映了在看到数据样本 x后 cj 成立的置信度。
3.贝叶斯定理
已知两个独立事件A和B,事件B发生的前提下,事件A发生的概率可以表示为P(A|B),即:
4.MAP分类准则
x 属于类别 c* 的概率:
利用贝叶斯准则转化为:
5.朴素贝叶斯分类器
朴素贝叶斯分类器采用了“属性条件独立性假设”,即每个属性独立地对分类结果发生影响。
为方便公式标记,不妨记P(C=c|X=x)为P(c|x),基于属性条件独立性假设,贝叶斯公式可重写为
其中d为属性数目,𝑥_𝑖 为 x 在第i个属性上的取值。
6.拉普拉斯修正
若某个属性值在训练集中没有与某个类同时出现过,则训练后的模型会出现 over-fitting 现象。为了避免其他属性携带的信息,被训练集中未出现的属性值“抹去”,在估计概率值时通常要进行“拉普拉斯修正”:
令 N 表示训练集 D 中可能的类别数,𝑁_𝑖表示第i个属性可能的取值数,则贝叶斯公式可修正为:
二、垃圾邮件分类
思路
读取垃圾邮件和正常邮件的数据,并将它们划分为训练集和测试集。
将邮件文本转换为特征向量,用于训练朴素贝叶斯分类器。
训练朴素贝叶斯分类器并对测试集进行分类,计算分类准确率。
代码
import os
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix
# 定义文本分割函数
def read_files_from_folder(folder_path, label):
emails = []
labels = []
for file_name in os.listdir(folder_path):
file_path = os.path.join(folder_path, file_name)
with open(file_path, 'r', encoding='gbk') as file:
email_text = file.read()
emails.append(email_text)
labels.append(label)
return emails, labels
# 定义获取训练和测试数据集的函数
def get_train_test_data(ham_folder, spam_folder):
ham_emails, ham_labels = read_files_from_folder(ham_folder, 0)
spam_emails, spam_labels = read_files_from_folder(spam_folder, 1)
emails = ham_emails + spam_emails
labels = ham_labels + spam_labels
return emails, labels
# 获取邮件数据
ham_folder = "D:/qq/3168619790/FileRecv/Ch04/email/ham"
spam_folder = "D:/qq/3168619790/FileRecv/Ch04/email/spam"
emails, labels = get_train_test_data(ham_folder, spam_folder)
# 定义生成词汇表的函数
def create_vocab_list(emails):
vocab_set = set([])
for email in emails:
word_list = re.findall(r'\b\w+\b', email.lower())
vocab_set = vocab_set | set(word_list)
return list(vocab_set)
# 生成词汇表
vocabList = create_vocab_list(emails)
# 定义词向量化的函数
def words_to_vector(vocab_list, input_email):
returnVec = [0] * len(vocab_list)
word_list = re.findall(r'\b\w+\b', input_email.lower())
for word in word_list:
if word in vocab_list:
returnVec[vocab_list.index(word)] = 1
return returnVec
# 定义朴素贝叶斯训练函数
def train_naive_bayes(train_matrix, train_category):
num_train_docs = len(train_matrix)
num_words = len(train_matrix[0])
p_spam = sum(train_category) / float(num_train_docs)
p0_num = np.ones(num_words)
p1_num = np.ones(num_words)
p0_denom = 2.0
p1_denom = 2.0
for i in range(num_train_docs):
if train_category[i] == 1:
p1_num += train_matrix[i]
p1_denom += sum(train_matrix[i])
else:
p0_num += train_matrix[i]
p0_denom += sum(train_matrix[i])
p1_vect = np.log(p1_num / p1_denom)
p0_vect = np.log(p0_num / p0_denom)
return p0_vect, p1_vect, p_spam
# 定义朴素贝叶斯测试函数
def classify_naive_bayes(vec2classify, p0_vec, p1_vec, p_class1):
p1 = sum(vec2classify * p1_vec) + np.log(p_class1)
p0 = sum(vec2classify * p0_vec) + np.log(1.0 - p_class1)
if p1 > p0:
return 1
else:
return 0
# 划分训练集和测试集
train_set, test_set, train_classes, test_classes = train_test_split(emails, labels, test_size=0.2, random_state=42)
# 将文本数据转换成特征向量
train_mat = []
for email in train_set:
train_mat.append(words_to_vector(vocabList, email))
# 训练朴素贝叶斯分类器
p0V, p1V, pSpam = train_naive_bayes(np.array(train_mat), np.array(train_classes))
# 测试朴素贝叶斯分类器
error_count = 0
for i in range(len(test_set)):
word_vector = words_to_vector(vocabList, test_set[i])
if classify_naive_bayes(word_vector, p0V, p1V, pSpam) != test_classes[i]:
error_count += 1
print("错误率:", float(error_count) / len(test_set) * 100)
结果
在测试过程中,分类器在5%的样本上做出了错误的预测,意味着分类器在这个测试集上表现良好。
三、错误与解决方法
错误:
这个由于文件编码不一致导致的,使用UTF-8编码对包含非UTF-8字符的文件进行解码时,就会引发错误。
解决方法:
可以使用文本编辑器或转码工具将文件的编码格式转换为UTF-8,我修改代码中读取文件的方式,代码with codecs.open('file.txt', 'r', encoding='gbk') as f,将用于指定打开文件时使用的编码方式的参数改为gbk。
四、总结
在这个实验中,使用朴素贝叶斯算法进行了垃圾邮件分类。首先,获取了训练和测试数据集,并生成了词汇表。然后,将文本数据转换成特征向量,并使用朴素贝叶斯算法进行训练。最后,对测试集进行分类,并计算了分类器的错误率。实验结果显示,在测试过程中,分类器在5%的样本上做出了错误的预测,这意味着分类器在这个测试集上表现良好。在实验过程中,可能会遇到一些问题,例如文件编码不一致导致的错误。为了解决这个问题,可以使用文本编辑器或转码工具将文件的编码格式转换为UTF-8,并相应地修改代码中读取文件的方式。