【初中生讲机器学习】9. 我是怎么用朴素贝叶斯实现垃圾邮件分类的?真的超全!

创建时间:2024-02-14
最后编辑时间:2024-02-15
作者:Geeker_LStar

你好呀~这里是 Geeker_LStar 的人工智能学习专栏,很高兴遇见你~
我是 Geeker_LStar,一名初三学生,热爱计算机和数学,我们一起加油~!
⭐(●’◡’●) ⭐ 那就让我们开始吧!

okkkk,大概十天以前我写了一篇关于朴素贝叶斯分类器原理的文章,but 没有更对应的实例代码,这篇来填坑~!
关于朴素贝叶斯的原理,这里:【初中生讲机器学习】5. 从概率到朴素贝叶斯算法,一篇带你看明白!

说到朴素贝叶斯,最出名的应用肯定就是垃圾邮件分类啦!这篇就来实现这个!

先讲大思路:判断一封邮件是否为垃圾邮件,我们需要从它所包含的词语入手(比如如果一封邮件包含 “彩票” 或 “广告”,那它很可能是一封垃圾邮件),也就是说,我们要求出 P ( 垃圾邮件 ∣ 词语 ) P(垃圾邮件|词语) P(垃圾邮件词语)。根据上一篇贝叶斯公式的推导, P ( 垃圾邮件 ∣ 词语 ) = P ( 词语 ∣ 垃圾邮件 ) P ( 垃圾邮件 ) P ( 词语 ) P(垃圾邮件|词语) = \frac{P(词语|垃圾邮件)P(垃圾邮件)}{P(词语)} P(垃圾邮件词语)=P(词语)P(词语垃圾邮件)P(垃圾邮件),等号右边这三个量,就是模型需要通过训练集学习出的。

在支持向量机的实例那一篇,我们是直接从 sklearn 中调用的数据集,但是这次不行了emm,so 我们需要自己下载:click here~,点 “同意协议”,然后下载 “trec06c.tgz” 那个,它是中文邮件数据集,一共有六万多封邮件数据。下载之后解压,注意和项目文件放在同一个文件夹中噢~

好,来看一下目录结构:

trec06c
	- data(存储所有邮件数据)
		- 000
			- 000
			- 001
			- ...
			- 299
		- 001
		- ...
		- 215
	- delay(没什么用)
		- index
	- full(存储所有邮件的标签:spam/ham)
		- index

嗯。。不过事情没有那么简单(()六万多组数据,内存会炸(我实验过了,的确炸了,but 我实在不想再去服务器训练一次了emm),所以我们可以拿出其中一些来用,我选了 3000 组数据放在一个新文件夹(test)当中。不用担心 3000 组不够,我训练的结果还是很不错的。


test 目录下只复制原 trec06c 目录下的 data 和 full 文件夹即可,并且注意删掉不用的数据,像这样:

data 文件夹

okkk,准备完数据我们来导入相关库
解释一下这些库的功能(注释里也有~):

  • re:它负责正则表达式(regular expression),可以使用正则表达式来匹配、搜索和替换文本。
  • jieba:它用来分词(结巴嘛)。
  • os:它是 Python 用来和操作系统打交道的库,功能很广,包括但不限于路径(文件目录)操作、进程管理、环境参数等。
  • codecs:它负责处理编码相关的问题,比如转换编码、解码等。
  • matplotlib:老生常谈了,数据可视化。
  • sklearn:这个之前讲过啦,不过提一句 TfidfVectorizer,它是专门用于计算文档中词语的 TF-IDF 值的一个函数,后面会详细讲哒。
'''第一步:导入相关库'''
import re    # 正则(字符串匹配)
import jieba    # 分词
import os    # 文件执行
import codecs    # 解码器(转换编码)
from sklearn import naive_bayes    # 朴素贝叶斯
from sklearn import svm
from sklearn.model_selection import train_test_split    # 划分训练集和测试集
from sklearn.metrics import roc_curve, recall_score, accuracy_score, roc_auc_score
from sklearn.feature_extraction.text import TfidfVectorizer
import matplotlib.pyplot as plt

andand,邮件数据这个比较难搞的是我们需要对数据进行一些预处理。毕竟鸢尾花数据集当中特征都给咱弄好了 but 这个没有,而且邮件散落在不同的文件夹。
好 ok 启动。

根据上面说的大思路,我们主要关注邮件中出现的词语,也就是邮件正文部分,所以我们可以大胆一点,把不是中文字符的东西全部去掉。去掉的部分包含邮件头、链接、电话号码这些。
(其实这些东西也能帮助判定是否为垃圾邮件,不过作用比较小,所以忽略也没什么大问题~)
这就需要正则表达式上场了。下面前两行正则表达式,帮我们去掉所有非中文字符,第三行去掉左右两端的空格。

# 去除非中文字符
def clear_email_content(string):
    string = re.sub(r"[^\u4e00-\u9fff]", "", string)
    string = re.sub(r"\s{2,}", "", string)
    return string.strip()

举个例子,我把一封邮件丢进去(这封邮件是 data/000/002),邮件的原文如下图:

原文

然后经过一番洗礼,输出是这样的:

输出

but,我们怎么对每一封邮件都这么操作呢?and 这个操作过后我们下一步干什么?别急,看过来:

first,先不管细节,但是多年的编程经验告诉我们, 我们需要先建立一个存储所有邮件数据的数组
然后,我们得遍历邮件内容路径(根据上面的目录结构,是 data 文件夹),遍历到每一封邮件之后把它的内容读取出来,进行去非中文处理,保存在临时变量中。
接着我们对临时变量(它保存了处理后的邮件内容)进行分词,得到一个分词列表,但是由于后续计算 tf-idf 等需要,得再把这个列表拼接成字符串,得到一个分词后的字符串(别看挺复杂,实际最终效果就是把原始内容用空格分成了一个个词)。
最后,我们把分词字符串加入到存储所有邮件数据的数组中,这样我们就处理完了一封邮件,可以重复上述流程来处理下一封啦!

先写一下伪代码:
真的这绝对是最好理解的伪代码,,,,几乎没几个代码()

# 伪代码
邮件内容列表 = []
def 读取邮件内容函数(邮件内容路径):
	for 子路径 in 邮件内容路径:
		if 还是目录:
			递归调用 读取邮件内容函数
		else:
			记录邮件内容的变量 = ''
			邮件内容 = 打开文件()
			for 每一行 in 邮件内容:= 去除非中文字符函数()
				变量 += 行
			关闭文件()
			分词列表 = 分词(变量)
			邮件字符串 = 将分词列表拼接为字符串(分词列表)
			将 邮件字符串 添加到 邮件内容列表

现在是不是感觉代码呼之欲出了((来来来:
真的我保证你一定会了,注释超详细,实在不行就对着上面思路 and 伪代码~
讲两个函数。第一个是 “codecs.open()”。这个函数主要是把邮件编码(或者说读出来的东西的编码)转为 gbk,要不然会乱码,记住一定要写 ignore errors,否则会报错。
第二个是 jieba.cut() 函数,它是 jieba 分词中的精准模式(另外两种分别是全模式和搜索引擎模式),它不会考虑所有可能的分词方式(全模式),而是只给出一种最有可能的分词方式,具有较高的召回率和较低的错误率。

# 正经代码
content_list = []    # 存储所有邮件内容的数组
data_path = "D:\PyProject\\algorithm\classification\\naive bayes\\test\data"    # 邮件内容路径

# 获取邮件正文内容,分词后加入邮件内容列表
def get_email_content(path):
    # 遍历 data 目录,读取每一封邮件
    files = os.listdir(path)  # 获取该路径下的目录和文件的路径,files 是一个路径列表
    for file in files:
        # 是目录就进入目录路径并继续遍历下一层,直到是文件为止
        if os.path.isdir(path + '/' + file):
            get_email_content(path + '/' + file)
        # 是文件就提取文件(邮件)内容
        else:
            email = ''    # 记录邮件内容
            f = codecs.open(path + '/' + file, 'r', 'gbk', errors='ignore')    # 转换为 gbk 编码
            # 对邮件数据进行预处理——调用 clear_mail_content() 函数
            for line in f:
                line = clear_email_content(line)
                email += line    # 拼接成一个字符串
            f.close()
            # 对处理后的内容进行分词(精准模式),去掉长度为 1 的词(字)
            email = [word for word in jieba.cut(email) if (word.strip != '' and len(word)>1)]
            # 将列表转化为字符串,词之间用空格分隔
            email = (' '.join(email))
            # 将分词后的内容加入邮件内容列表(二维数组,每一个元素都是一封分词后的邮件)
            content_list.append(email)
get_email_content(data_path)

ok~这样所有邮件数据就读取完了,接下来把所有邮件的标签也这么搞一下,方便后续工作。

还是一样的套路,建一个数组,然后遍历 test/full/index.txt,如果标签是 spam,说明是垃圾邮件,就记录为 1,如果是 ham 就记录为 0.

label_list = []    # 存储所有邮件标签的数组
label_path = "D:\PyProject\\algorithm\classification\\naive bayes\\test\\full\index.txt"

# 将邮件标签存入数组中,1 代表垃圾邮件,0 代表正常邮件
def get_email_label(path):
    f = open(path, 'r')
    # 将邮件标签转化为 0 和 1,添加到列表中
    for line in f:
        # 垃圾邮件 spam
        if line[0] == 's':
            label_list.append('1')
        # 正常邮件 ham
        elif line[0] == 'h':
            label_list.append('0')
get_email_label(label_path)

好哒!恭喜我们,已经完成了数据预处理!
接下来…好戏开场!

我们现在已经有了所有邮件分词后的数据,
回到最开始讲的大思路。模型的目标是求出 P ( 词语 ) P(词语) P(词语) P ( 词语 ∣ 垃圾邮件 ) P(词语∣垃圾邮件) P(词语垃圾邮件) P ( 垃圾邮件 ) P(垃圾邮件) P(垃圾邮件) P ( 垃圾邮件 ) P(垃圾邮件) P(垃圾邮件) 还算好求,用垃圾邮件数量除以正常邮件数量就 ok 了,重点在词语上——我们怎么求出一个词语出现的概率 and 在垃圾邮件中,这个词语出现的概率?
难不成遍历存储所有邮件内容的数组???那这工作量也有点太大了。而且现在的所有数据都还是文字形式,是没法直接拿去训练的,我们必须得想办法把它们转化为**实数(矩阵)**的形式。

别担心,TF-IDF 来帮我们啦!

TF-IDF,中文名 “词频-逆文件概率”,英文全称 term frequency–inverse document frequency,常用于自然语言处理(NLP)。
它的主要思想是:如果一个词在该文档中出现的概率高,而在其它文档中出现的概率低,那么这个词(对于这个文件)有较好的代表性。

用到我们的任务当中,如果一些词在垃圾邮件中出现的概率高,而在正常邮件中出现的概率低,那么这些词可以较好地代表垃圾邮件。再通俗一点就是,有这些词的邮件很有可能是垃圾邮件。

ok,知道了我们用它干什么,再来看看它是怎么计算的。
先来看 TF,TF 的意思是词频,也就是一个词在文档中出现的次数。但是为了避免这个次数在长文件中比在短文件中多而影响判断,我们还需要对词频做归一化处理,通常是用词频除以文档总词数,得到 TF 值。
公式如下,其中 T F i , j TF_{i, j} TFi,j 表示该词条在该文档中的 TF 值,分子 n i , j n_{i,j} ni,j 表示词条 t i t_i ti 在文档 d j d_j dj 中出现的次数,分母表示文档的总词数。
T F i , j = n i , j ∑ k k i , j TF_{i, j} = \frac {n_{i,j}}{\sum_{k} k_{i,j}} TFi,j=kki,jni,j
emmm 但是,光有 TF 是不够的,因为有些词比如 “我们”、“他们” 可能在很多文件中的 TF 值都很高(即都出现了很多次),那这些词就不具有代表性了。为此,我们找来了 IDF。
牢记,TF-IDF 是为了衡量一个词对某个文档而言是否足够有代表性
IDF 和词条在所有文档中的出现频率是反过来的。也就是说,如果一个词在很多文档中都出现了,那么它的 IDF 会较低,而如果它只在很少的文档中出现,那么它的 IDF 会很高。
公式如下,其中 N 为文档总数,j 是包含词条 t i t_i ti 的文档数,加 1 是为了防止出现分母为 0 的情况(类似拉普拉斯平滑)。
I D F = l g N 1 + ∣ j : t i ∈ d j ∣ IDF = lg\frac{N}{1+|j:t_i ∈d_j|} IDF=lg1+j:tidjN

综上,如果某词条在某文档中出现的次数多,而在其它文档中出现的次数少,那么它会同时拥有较高的 TF 值和 IDF 值,它的 TF-IDF 值就等于 TF 值和 IDF 值的乘积,即:
T F − I D F = T F × I D F = n i , j ∑ k k i , j × l g N 1 + ∣ j : t i ∈ d j ∣ TF-IDF = TF × IDF = \frac{n_{i,j}}{\sum_{k} k_{i,j}} ×lg\frac{N}{1+|j:t_i ∈d_j|} TFIDF=TF×IDF=kki,jni,j×lg1+j:tidjN

最后放一张超好看的图来总结:

总结

okkkk,用 TF-IDF,我们就可以用之前已经统计好的(分好词的邮件)计算每个词的 TF-IDF 值了~ Python 提供了相关的方法——sklearn 库中的 TfidfVectorizer
先把代码放在这,然后再来讲。

# 将每一封邮件转化为词频矩阵(稀疏矩阵)
# TF-IDF,词频-逆文件频率,自然语言处理中常用的方法(加权技术)
# TF-IDF 用以评估一字词对于一个文件的重要程度。
# 字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库(其他文章)中出现的频率成反比下降。
# 即,一个词语在一篇文章中出现次数越多,同时在所有文档中出现次数越少,越能够代表该文章。
def tfidf(list):
    tf = TfidfVectorizer()    # 实例化
    data = tf.fit_transform(list)    # 训练,获得每一个词的 tf-idf
    global X
    X = data.toarray()    # 二维数组,每一个元素都是一个邮件的词频矩阵
tfidf(content_list)

看函数体中的第二行,data 变量中保存了每一封邮件中的每一个词的 TF-IDF 值,从第一封邮件到第三千封邮件。不过不是数组的形式,输出以后会是这样的:
“0” 代表第一封邮件,“0” 后面的整数是这个词语在所有词语构成的词语表中的编码(索引),最后那个小数才是这个词的 TF-IDF 值

在这里插入图片描述

再看第四行,“X” 是我们把原始数据转化为可用于训练的数据的结果(和 SVM 实例里面的鸢尾花数据集很像),X 是一个二维数组,数组中的每个元素(第一层)都代表一封邮件,“邮件” 里面(第二层)存储着词语的信息,和之前不同的是词语已经被转化成了一个个 TF-IDF 值,也就是词频矩阵
其实就相当于把 data 转成数组,同一封邮件的词的 TF-IDF 构成一个元素,所有的元素(邮件)构成 X。
类似下面这样,嗷不要奇怪为什么一堆是 0,因为词语太多了,而一封邮件肯定不会包含所有的词,那些不被这封邮件包含的词在这封邮件中的 TF-IDF 值就是 0。呃有点绕但是其实还蛮好理解的啦~
X

ok!恭喜我们!好戏部分已经搞定啦~~接下来就是常规训练 & 测试环节咯。

这段就直接放在这了()实在没什么可讲的了,之前 SVM 和 KNN 的实例已经讲过 N 遍了。

'''第三步:训练 and 测试'''
# 获取并划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, label_list, test_size=0.3, random_state=218)
# 用三种模型进行训练,比较它们的结果
# 多项式贝叶斯
mul_bayes = naive_bayes.MultinomialNB()    # 实例化
mul_bayes.fit(X_train, y_train)    # 训练
y1_predict = mul_bayes.predict(X_test)    # 预测(测试)
y1_proba = mul_bayes.predict_proba(X_test)    # 预测属于两个类别(正常/垃圾)的概率
# 伯努利贝叶斯
bernoulli_bayes = naive_bayes.BernoulliNB()
bernoulli_bayes.fit(X_train, y_train)
y2_predict = bernoulli_bayes.predict(X_test)    # 预测(测试)
y2_proba = bernoulli_bayes.predict_proba(X_test)
# 支持向量机
svm = svm.SVC(kernel="rbf", C=1, gamma="auto", probability=True)
svm.fit(X_train, y_train)
y3_predict = svm.predict(X_test)    # 预测(测试)
y3_proba = svm.predict_proba(X_test)

# 输出测试结果
# pos_label:正样本标签(本例中正样本为垃圾邮件)
print("多项式朴素贝叶斯准确率:", accuracy_score(y_test, y1_predict))
print("多项式朴素贝叶斯召回率:", recall_score(y_test, y1_predict, pos_label="1"))
print("多项式朴素贝叶斯 AUC 值:", roc_auc_score(y_test, y1_proba[:, 1]))
print("伯努利朴素贝叶斯准确率:", accuracy_score(y_test, y2_predict))
print("伯努利朴素贝叶斯召回率:", recall_score(y_test, y2_predict, pos_label="1"))
print("伯努利朴素贝叶斯 AUC 值:", roc_auc_score(y_test, y2_proba[:, 1]))
print("支持向量机准确率:", accuracy_score(y_test, y3_predict))
print("支持向量机召回率:", recall_score(y_test, y3_predict, pos_label="1"))
print("支持向量机 AUC 值:", roc_auc_score(y_test, y3_proba[:, 1]))

嗯!然后我们来画一个 ROC 曲线嘿嘿,之前在这篇【初中生讲机器学习】6. 分类算法中常用的模型评价指标有哪些?here! 里面我讲过 ROC。

注释里写了,画 ROC 需要知道模型预测数据为正样本的概率,然后再用 roc_curve() 得到真正率 TPR,假正率 FPR。如果不知道是怎么得到的,可以参考上面放的那篇文章~

# 绘制 ROC 曲线图
# 获取模型对测试集数据的预测情况(属于两个类别的概率)
# ROC 曲线需要获取模型预测数据为正样本的概率,即 [:, 1]
score_m = mul_bayes.predict_proba(X_test)[:, 1]
score_b = bernoulli_bayes.predict_proba(X_test)[:, 1]
score_s = svm.predict_proba(X_test)[:, 1]
#使用 roc_curve 方法得到三个模型的真正率 TP,假正率 FP和阈值 threshold
fpr_m, tpr_m, thres_m = roc_curve(y_test, score_m, pos_label="1")
fpr_b, tpr_b, thres_b = roc_curve(y_test, score_b, pos_label="1")
fpr_s, tpr_s, thres_s = roc_curve(y_test, score_s, pos_label="1")

最后就是画图环节啦~代码直接放在这了,有注释。

# 创建画布
fig, ax = plt.subplots(figsize=(10,8))
# 自定义标签名称(使用 AUC 值)
ax.plot(fpr_m,tpr_m,linewidth=2,
        label='MultinomialNB (AUC={})'.format(str(round(roc_auc_score(y_test, y1_proba[:, 1]), 3))))
ax.plot(fpr_b,tpr_b,linewidth=2,
        label='BernoulliNB (AUC={})'.format(str(round(roc_auc_score(y_test, y2_proba[:, 1]), 3))))
ax.plot(fpr_s,tpr_s,linewidth=2,
        label='SVM (AUC={})'.format(str(round(roc_auc_score(y_test, y3_proba[:, 1]), 3))))
# 绘制对角线
ax.plot([0,1],[0,1],linestyle='--',color='grey')
# 调整字体大小
plt.legend(fontsize=12)
# 展现画布
plt.show()

ok 啊!大功告成!!来看看投喂三千组数据是什么结果!~

结果

由此看来,两个贝叶斯模型表现的还是不错的!SVM 的准确率有点低了emm,可能是因为它有较高的召回率(查全率),导致部分非垃圾邮件也被分到了垃圾邮件,准确率就变低了。

来看看 ROC,它们仨都很好呢!

ROC

综合来看,指标最好的是多项式朴素贝叶斯

完整代码:

# 垃圾邮件检索
# 朴素贝叶斯
# TF-IDF 技术
# 首先对数据进行预处理,然后利用 tf-idf 将每封邮件转化为词频矩阵,最后训练模型
# 数据集下载:https://plg.uwaterloo.ca/~gvcormac/treccorpus06/

'''第一步:导入相关库'''
import re    # 正则(字符串匹配)
import jieba    # 分词
import os    # 文件执行
import codecs    # 解码器
from sklearn import naive_bayes    # 朴素贝叶斯
from sklearn import svm
from sklearn.model_selection import train_test_split    # 划分训练集和测试集
from sklearn.metrics import roc_curve, recall_score, accuracy_score, roc_auc_score
from sklearn.feature_extraction.text import TfidfVectorizer
import matplotlib.pyplot as plt

'''第二步:数据预处理'''
content_list = []
label_list = []
# data_path = "D:\PyProject\\algorithm\classification\\naive bayes\\trec06c\data"
# label_path = "D:\PyProject\\algorithm\classification\\naive bayes\\trec06c\\full\index"
# 原始数据集过大,此处选择 3000 组数据,900 组作为测试集
data_path = "D:\PyProject\\algorithm\classification\\naive bayes\\test\data"
label_path = "D:\PyProject\\algorithm\classification\\naive bayes\\test\\full\index.txt"

# 数据预处理
# 去除非中文字符
def clear_email_content(string):
    string = re.sub(r"[^\u4e00-\u9fff]", "", string)
    string = re.sub(r"\s{2,}", "", string)
    return string.strip()

# 获取邮件正文内容,分词后加入邮件内容列表
def get_email_content(path):
    # 遍历 data 目录,读取每一封邮件
    files = os.listdir(path)  # 获取该路径下的目录和文件的路径,files 是一个路径列表
    for file in files:
        # 是目录就进入目录路径并继续遍历下一层,直到是文件为止
        if os.path.isdir(path + '/' + file):
            get_email_content(path + '/' + file)
        # 是文件就提取文件(邮件)内容
        else:
            email = ''    # 记录邮件内容
            f = codecs.open(path + '/' + file, 'r', 'gbk', errors='ignore')    # 转换为 gbk 编码
            # 对邮件数据进行预处理——调用 clear_mail_content() 函数
            for line in f:
                line = clear_email_content(line)
                email += line    # 拼接成一个字符串
            f.close()
            # 对处理后的内容进行分词(精准模式),去掉长度为 1 的词(字)
            email = [word for word in jieba.cut(email) if (word.strip != '' and len(word)>1)]
            # 将列表转化为字符串,词之间用空格分隔
            email = (' '.join(email))
            # 将分词后的内容加入邮件内容列表(二维数组,每一个元素都是一封分词后的邮件)
            content_list.append(email)
get_email_content(data_path)

# 将邮件标签存入数组中,1 代表垃圾邮件,0 代表正常邮件
def get_email_label(path):
    f = open(path, 'r')
    # 将邮件标签转化为 0 和 1,添加到列表中
    for line in f:
        # 垃圾邮件 spam
        if line[0] == 's':
            label_list.append('1')
        # 正常邮件 ham
        elif line[0] == 'h':
            label_list.append('0')
get_email_label(label_path)

# 将每一封邮件转化为词频矩阵(稀疏矩阵)
# TF-IDF,词频-逆文件频率,自然语言处理中常用的方法(加权技术)
# TF-IDF 用以评估一字词对于一个文件的重要程度。
# 字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库(其他文章)中出现的频率成反比下降。
# 即,一个词语在一篇文章中出现次数越多,同时在所有文档中出现次数越少,越能够代表该文章。
def tfidf(list):
    tf = TfidfVectorizer()    # 实例化
    data = tf.fit_transform(list)    # 训练,获得每一个词的 tf-idf
    global X
    X = data.toarray()    # 二维数组,每一个元素都是一个邮件的词频矩阵
tfidf(content_list)

'''第三步:训练 and 测试'''
# 获取并划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, label_list, test_size=0.3, random_state=218)
# 用三种模型进行训练,比较它们的结果
# 多项式贝叶斯
mul_bayes = naive_bayes.MultinomialNB()    # 实例化
mul_bayes.fit(X_train, y_train)    # 训练
y1_predict = mul_bayes.predict(X_test)    # 预测(测试)
y1_proba = mul_bayes.predict_proba(X_test)    # 预测属于两个类别(正常/垃圾)的概率
# 伯努利贝叶斯
bernoulli_bayes = naive_bayes.BernoulliNB()
bernoulli_bayes.fit(X_train, y_train)
y2_predict = bernoulli_bayes.predict(X_test)    # 预测(测试)
y2_proba = bernoulli_bayes.predict_proba(X_test)
# 支持向量机
svm = svm.SVC(kernel="rbf", C=1, gamma="auto", probability=True)
svm.fit(X_train, y_train)
y3_predict = svm.predict(X_test)    # 预测(测试)
y3_proba = svm.predict_proba(X_test)

# 输出测试结果
# pos_label:正样本标签(本例中正样本为垃圾邮件)
print("多项式朴素贝叶斯准确率:", accuracy_score(y_test, y1_predict))
print("多项式朴素贝叶斯召回率:", recall_score(y_test, y1_predict, pos_label="1"))
print("多项式朴素贝叶斯 AUC 值:", roc_auc_score(y_test, y1_proba[:, 1]))
print("伯努利朴素贝叶斯准确率:", accuracy_score(y_test, y2_predict))
print("伯努利朴素贝叶斯召回率:", recall_score(y_test, y2_predict, pos_label="1"))
print("伯努利朴素贝叶斯 AUC 值:", roc_auc_score(y_test, y2_proba[:, 1]))
print("支持向量机准确率:", accuracy_score(y_test, y3_predict))
print("支持向量机召回率:", recall_score(y_test, y3_predict, pos_label="1"))
print("支持向量机 AUC 值:", roc_auc_score(y_test, y3_proba[:, 1]))

# 绘制 ROC 曲线图
# 获取模型对测试集数据的预测情况(属于两个类别的概率)
# ROC 曲线需要获取模型预测数据为正样本的概率,即 [:, 1]
score_m = mul_bayes.predict_proba(X_test)[:, 1]
score_b = bernoulli_bayes.predict_proba(X_test)[:, 1]
score_s = svm.predict_proba(X_test)[:, 1]
#使用 roc_curve 方法得到三个模型的真正率 TP,假正率 FP和阈值 threshold
fpr_m, tpr_m, thres_m = roc_curve(y_test, score_m, pos_label="1")
fpr_b, tpr_b, thres_b = roc_curve(y_test, score_b, pos_label="1")
fpr_s, tpr_s, thres_s = roc_curve(y_test, score_s, pos_label="1")
# 创建画布
fig, ax = plt.subplots(figsize=(10,8))
# 自定义标签名称(使用 AUC 值)
ax.plot(fpr_m,tpr_m,linewidth=2,
        label='MultinomialNB (AUC={})'.format(str(round(roc_auc_score(y_test, y1_proba[:, 1]), 3))))
ax.plot(fpr_b,tpr_b,linewidth=2,
        label='BernoulliNB (AUC={})'.format(str(round(roc_auc_score(y_test, y2_proba[:, 1]), 3))))
ax.plot(fpr_s,tpr_s,linewidth=2,
        label='SVM (AUC={})'.format(str(round(roc_auc_score(y_test, y3_proba[:, 1]), 3))))
# 绘制对角线
ax.plot([0,1],[0,1],linestyle='--',color='grey')
# 调整字体大小
plt.legend(fontsize=12)
# 展现画布
plt.show()


OK!!!以上就是垃圾邮件分类器的完整实现啦!!快去试试吧~~

这篇文章用朴素贝叶斯算法实现了垃圾邮件分类,希望对你有所帮助!⭐
欢迎三连!!一起加油!🎇
——Geeker_LStar

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/388171.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java学习第十四节之多维数组和Arrays类讲解

多维数组 package array;public class ArrayDemo05 {public static void main(String[] args) {//[4][2] 面向对象/*1,2 array[0]2,3 array[1]3,4 array[2]4,5 array[3]*/int[][] array {{1,2},{2,3},{3,4},{4,5}};for (int i 0; i <array.length; i) {for (int…

Pandas数据库大揭秘:read_sql、to_sql 参数详解与实战篇【第81篇—Pandas数据库】

Pandas数据库大揭秘&#xff1a;read_sql、to_sql 参数详解与实战篇 Pandas是Python中一流的数据处理库&#xff0c;而数据库则是数据存储和管理的核心。将两者结合使用&#xff0c;可以方便地实现数据的导入、导出和分析。本文将深入探讨Pandas中用于与数据库交互的两个关键方…

Linux 基础/子目录分配/文件路径

在Linux系统中&#xff0c;整个系统只具有一个根目录“/”&#xff0c;用斜杠表示。根目录是整个文件系统的顶层目录&#xff0c;在他下面可以创建其他的目录和文件。 Linux中的子目录分配&#xff1a; /bin - 基本命令的二进制文件&#xff0c;这些命令可供所有用户使用&am…

数据结构第十四天(树的存储/双亲表示法)

目录 前言 概述 接口&#xff1a; 源码&#xff1a; 测试函数&#xff1a; 运行结果&#xff1a; 往期精彩内容 前言 孩子&#xff0c;一定要记得你的父母啊&#xff01;&#xff01;&#xff01; 哈哈&#xff0c;今天开始学习树结构中的双亲表示法&#xff0c;让孩…

SB+AVL——二刷错误总结

码云 SBTree insert中对头节点的处理 void Insert(int val){Node* node new Node(val);// 找插入位置if (_root nullptr){_root node;return;}else{Node* pre _root, *head _root;while (head){pre head;if (head->_val < val) head head->_right;else if (h…

P1259 黑白棋子的移动题解

题目 有2n个棋子排成一行&#xff0c;开始为位置白子全部在左边&#xff0c;黑子全部在右边&#xff0c;如下图为n5的情况&#xff1a; 移动棋子的规则是&#xff1a;每次必须同时移动相邻的两个棋子&#xff0c;颜色不限&#xff0c;可以左移也可以右移到空位上去&#xff0c…

【C++】内存管理方式--new/delete

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

Repo命令使用实例(三十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

(01)Hive的相关概念——架构、数据存储、读写文件机制

目录 一、架构及组件介绍 1.1 Hive整体架构 1.2 Hive组件 1.3 Hive数据模型&#xff08;Data Model&#xff09; 1.3.1 Databases 1.3.2 Tables 1.3.3 Partitions 1.3.4 Buckets 二、Hive读写文件机制 2.1 SerDe 作用 2.2 Hive读写文件流程 2.2.1 读取文件的过程 …

BUGKU-WEB 你必须让他停下

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 图片会消失,那应该是使用了js来控制根据提示,那就是要停止js才会看到flag (也就是要抓包,不要陷入停止js的思维) 相关工具 F12大法Burp Suit抓包工具 解题步骤 出现图片的时候,源码中确实出现…

ICLR 2023#Learning to Compose Soft Prompts for Compositional Zero-Shot Learning

组合零样本学习&#xff08;CZSL&#xff09;中Soft Prompt相关工作汇总&#xff08;一&#xff09; 文章目录 组合零样本学习&#xff08;CZSL&#xff09;中Soft Prompt相关工作汇总&#xff08;一&#xff09;ICLR 2023#Learning to Compose Soft Prompts for Compositional…

Android之Android.bp文件格式语法(一百八十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

力扣hot3--并查集+哈希

第一想法是排个序然后遍历一遍&#xff0c;but时间复杂度就超啦 并查集居然与哈希结合了&#xff08;&#xff09; 已经好久没用过并查集了&#xff0c;&#xff0c;&#xff0c;我们用哈希表f_node中来记录原结点的父节点&#xff0c;其中key是原结点&#xff0c;value是父节点…

Github项目推荐-Tiny-Rdm

项目地址 GitHub - tiny-craft/tiny-rdm: A Modern Redis GUI Client 项目简述 一个开源的Redis管理工具&#xff0c;有漂亮的界面和丰富的功能。使用的编程语言如下 项目截图

【Qt】环境安装与初识

目录 一、Qt背景介绍 二、搭建Qt开发环境 三、新建工程 四、Qt中的命名规范 五、Qt Creator中的快捷键 六、QWidget基础项目文件详解 6.1 .pro文件解析 6.2 widget.h文件解析 6.3 widget.cpp文件解析 6.4 widget.ui文件解析 6.5 main.cpp文件解析 七、对象树 八、…

对什么都不感兴趣,怎么办?

这大概是现代社会&#xff0c;最为常见的都市病。 很多人大抵都明白&#xff1a;好的生活是什么样的呢&#xff1f;要有一个大目标&#xff0c;再分拆成一个个小目标&#xff0c;每天朝着目标前进&#xff0c;看着自己的进步和成长&#xff0c;转化为成就感和动力 —— 对不对&…

揭秘Angular世界的奥秘:全面提升你的前端开发技能!

介绍&#xff1a;Angular是一个由Google维护的开源JavaScript框架&#xff0c;专为构建Web应用程序而设计&#xff0c;特别适合开发大型单页应用&#xff08;SPA&#xff09;。以下是对Angular的详细介绍&#xff1a; 技术栈&#xff1a;Angular使用HTML作为模板语言&#xff0…

C++集群聊天服务器 nginx+redis安装 笔记 (中)

一、nginx安装 nginx: download 下载nginx安装包 hehedalinux:~/package$ tar -zvxf nginx-1.24.0.tar.gz nginx-1.24.0/ nginx-1.24.0/auto/ nginx-1.24.0/conf/ nginx-1.24.0/contrib/ nginx-1.24.0/src/ nginx-1.24.0/configure nginx-1.24.0/LICENSE nginx-1.24.0/README…

言语残疾和言语残疾分级

言语残疾和言语残疾分级 言语残疾&#xff0c;指各种原因导致的不同程度的言语障碍&#xff0c;经治疗一年以上不愈或病程超过两年&#xff0c;而不能或难以进行正常的言语交流活动&#xff0c;以致影响其日常生活和社会参与。包括&#xff1a;失语、运动性构音障碍、器质性构音…

黑马程序员——移动Web——day02

目录 空间转换 空间转换简介平移视距旋转左手法则rotate3d-了解立体呈现案例-3d导航缩放动画 动画实现步骤animation复合属性animation拆分写法案例-走马灯精灵动画多组动画综合案例-全名出游 背景云彩位置和动画文字动画 1.空间转换 空间转换简介 空间&#xff1a;是从坐标…