机器学习——使用朴素贝叶斯分类器实现垃圾邮件检测(python代码+数据集)

系列文章目录

机器学习——scikit-learn库学习、应用
机器学习——最小二乘法拟合曲线、正则化
机器学习——使用朴素贝叶斯分类器实现垃圾邮件检测(python代码+数据集)



1、概念阐述

贝叶斯公式: P ( A ∣ B ) = P ( A ) P ( B ∣ A ) P ( B ) P(A \mid B)=\frac{P(A) P(B \mid A)}{P(B)} P(AB)=P(B)P(A)P(BA)
贝叶斯概念可以参考这个视频,我觉得还不错。
对于垃圾邮件分类预测,简单来说就是判断一封邮件是垃圾邮件的概率和是正常邮件的概率,哪一个概率大就判定为是哪一种类型的邮件。以 h + h^{+} h+为垃圾邮件, h − h^{-} h为正常邮件,D代表需要验证的邮件,d代表邮件里面的的单词如下:
D = d 1 , d 2 , d 3 , d 4 , d 5 . . . d n D = d_{1} ,d_{2} ,d_{3} ,d_{4} ,d_{5} ...d_{n} D=d1,d2,d3,d4,d5...dn
则一封测试邮件为垃圾邮件和正常邮件的概率公式如下: P ( h + ∣ D ) = P ( h + ) ∗ P ( D ∣ h + ) P ( D ) P\left(h^{+} \mid D\right)=\frac{P\left(h^{+}\right) * P\left(D \mid h^{+}\right)}{P(D)} P(h+D)=P(D)P(h+)P(Dh+)
P ( h − ∣ D ) = P ( h − ) ∗ P ( D ∣ h − ) P ( D ) P\left(h^{-} \mid D\right)=\frac{P\left(h^{-}\right) * P\left(D \mid h^{-}\right)}{P(D)} P(hD)=P(D)P(h)P(Dh)
P ( h − ∣ D ) P\left(h^{-} \mid D\right) P(hD) :测试邮件为正常邮件的概率
P ( h + ∣ D ) P\left(h^{+} \mid D\right) P(h+D) :测试邮件为垃圾邮件的概率
P ( h − ) P\left(h^{-}\right) P(h) :一封邮件为正常邮件的概率(先验数据集)
P ( h + ) P\left(h^{+}\right) P(h+):一封邮件为垃圾邮件的概率(先验数据集)
下面三个公式描述的可能不太对
P ( D ∣ h + ) P\left(D \mid h^{+}\right) P(Dh+) :垃圾邮件是测试邮件的概率
P ( D ∣ h − ) P\left(D \mid h^{-}\right) P(Dh) :正常邮件是测试邮件的概率
P ( D ) P(D) P(D) :测试邮件的概率

因为独立事件间的概率计算更加简单,为了简便计算,朴素贝叶斯假定所有输入事件之间是相互独立的。也就是邮件里的每个单词相互独立与出现的先后顺序无关。由朴素贝叶斯定理公式可以分解为如下:
P ( h + ∣ D ) = P ( h + ) ∗ P ( d 1 ∣ h + ) ∗ P ( d 2 ∣ h + ) ∗ . . . ∗ P ( d n ∣ h + ) P ( d 1 ) ∗ P ( d 2 ) ∗ . . . ∗ P ( d n ) P\left(h^{+} \mid D\right)=\frac{P\left(h^{+}\right) * P\left(d_{1 } \mid h^{+}\right)* P\left(d_{2 } \mid h^{+}\right)*...* P\left(d_{n } \mid h^{+}\right)}{P(d_{1})*P(d_{2})*...*P(d_{n})} P(h+D)=P(d1)P(d2)...P(dn)P(h+)P(d1h+)P(d2h+)...P(dnh+)
P ( h − ∣ D ) = P ( h − ) ∗ P ( d 1 ∣ h − ) ∗ P ( d 2 ∣ h − ) ∗ . . . ∗ P ( d n ∣ h − ) P ( d 1 ) ∗ P ( d 2 ) ∗ . . . ∗ P ( d n ) P\left(h^{-} \mid D\right)=\frac{P\left(h^{-}\right) * P\left(d_{1 } \mid h^{-}\right)* P\left(d_{2 } \mid h^{-}\right)*...* P\left(d_{n } \mid h^{-}\right)}{P(d_{1})*P(d_{2})*...*P(d_{n})} P(hD)=P(d1)P(d2)...P(dn)P(h)P(d1h)P(d2h)...P(dnh)
P ( d n ∣ h + ) P\left(d_{n } \mid h^{+}\right) P(dnh+):代表了测试邮件中的一个单词在垃圾邮件邮件中刚出现的概率(先验数据集), P ( d n ∣ h − ) P\left(d_{n } \mid h^{-}\right) P(dnh)同理。
P ( h + ∣ D ) P\left(h^{+} \mid D\right) P(h+D)整个式子就是求:( P ( h − ) P\left(h^{-}\right) P(h)乘测试邮件中的每个单词在垃圾邮件中出现的概率) 除上(每个单词在垃圾邮件和正常邮件中出现的概率) P ( h − ∣ D ) P\left(h^{-} \mid D\right) P(hD)同理。

但在实际计算中为了防止概率太小导致最后结果四舍五入约等于0,会把上面的概率取log再相加。
因为 P ( h + ∣ D ) P\left(h^{+} \mid D\right) P(h+D) P ( h − ∣ D ) P\left(h^{-} \mid D\right) P(hD)的分母一样,我们的目的是比较两者的概率大小,为了方便计算把分母省略了。
以上参考了B站唐宇迪的讲解。

这段代码实现了一个朴素贝叶斯分类器来对电子邮件进行分类,其中包括读取数据、文本预处理、训练分类器和预测新邮件的过程。 具体来说,代码中使用get_data 函数从指定目录 DATA_DIR 中读取数据,并将 Spam 和 Ham 的电子邮件内容分别存储在 data 和 target 列表中。在数据预处理过程中,使用 preprocess 函数对文本进行处理,包括转为小写、去除标点符号和停用词等操作。接下来实现了 NaiveBayesClassifier 类的 fit 和 predict 方法,其中 fit方法用于训练朴素贝叶斯分类器,predict 方法用于对新邮件进行分类。 在 fit 方法中,首先定义了四个 defaultdict类型的变量,包括每个类别的文档数 class_total,每个类别中所有单词出现次数之和 word_total,每个类别中每个单词出现次数word_given_class 和词汇表 vocabulary。然后遍历训练集 X 和标签 y,使用 preprocess 函数对文本进行处理,将处理后的文本和标签一起用于更新 class_total、word_total、word_given_class 和vocabulary 等变量。 在 predict方法中,首先使用训练集中每个类别的文档数计算了每个类别的先验概率的对数,这样可以避免概率值太小而导致下溢。然后遍历待分类邮件 X,使用preprocess 函数对文本进行处理,计算该邮件属于每个类别的概率的对数,最终选择概率最大值对应的类别作为预测结果。

2、代码

代码中的一些函数使用说明参考:http://t.csdn.cn/VGQjB

读取数据

DATA_DIR = 'enron'  # 数据集地址
target_names = ['ham', 'spam']  # 正常、 垃圾 
stopwords = set(open('stopwords.txt', 'r').read().splitlines())   # .splitlines() 按换行符分割

def get_data(DATA_DIR):
    subfolders = ['enron%d' % i for i in range(1,7)]  # 返回enron1-enron7列表
    data = []
    target = []
    for subfolder in subfolders: # 对enron1-enron7依次遍历
        # spam
        spam_files = os.listdir(os.path.join(DATA_DIR, subfolder, 'spam')) # 获文件夹下的所有文件 返回一个列表
        for spam_file in spam_files: # 依次打开返回的文件
            with open(os.path.join(DATA_DIR, subfolder, 'spam', spam_file), encoding="latin-1") as f:
                data.append(f.read())
                target.append(1)  # 垃圾邮件标签 为1
        # ham
        ham_files = os.listdir(os.path.join(DATA_DIR, subfolder, 'ham'))
        for ham_file in ham_files:
            with open(os.path.join(DATA_DIR, subfolder, 'ham', ham_file), encoding="latin-1") as f:
                data.append(f.read())
                target.append(0)  # 正常邮件标签 为0
    return data, target

数据转换

def preprocess(text):
    """
    对文本进行处理,包括去除标点、转为小写、去除停用词等操作。
    """
    text = text.lower()  # 转为小写
    text = re.sub(f'[{string.punctuation}]', ' ', text)  # 去除标点符号
    text = [word for word in text.split() if word not in stopwords]  # 去除停用词
    return text

朴素贝叶斯函数

训练和预测

class NaiveBayesClassifier():
    def __init__(self):
        self.vocabulary = set()  # 词汇表
        self.class_total = defaultdict(int)  # 每个类别的文档数
        self.word_total = defaultdict(int)  # 每个类别中所有单词出现次数之和
        self.word_given_class = defaultdict(lambda: defaultdict(int))  # 每个类别中每个单词出现次数

    def fit(self, X, y):
        """
        训练分类器,其中 X 为训练集数据,y 为训练集标签。
        """
        for text, label in zip(X, y):
            words = preprocess(text)  # 对文本进行处理,包括去除标点、转为小写、去除停用词等操作。
            self.class_total[label] += 1   # 该类别文档数加1
            for word in words:             # 遍历每一个单词
                self.vocabulary.add(word)   # 加入词汇表
                self.word_given_class[label][word] += 1  # 该类别中该单词出现次数加1
                self.word_total[label] += 1  # 该类别所有单词出现次数之和加1

    def predict(self, X):
        """
        对新邮件进行分类,其中 X 为待分类邮件。
        """
        log_priors = {}  # 存储每个类别的先验概率的对数(用于避免下溢)
        for c in self.class_total.keys():
            #  log(每个类别的文档数/文档数)  也就是训练集正常邮件和垃圾邮件占总邮件的比例
            log_priors[c] = math.log(self.class_total[c] / sum(self.class_total.values())) 

        predictions = []
        for text in X:  # 遍历测试集的每一个邮件
            words = preprocess(text) # 对文本进行处理,包括去除标点、转为小写、去除停用词等操作。

            log_probs = {}
            for c in self.class_total.keys(): #遍历两个类别  正常和垃圾邮件类别
                log_probs[c] = log_priors[c]
                for word in words:  # 遍历每个单词
                    if word in self.vocabulary:  # 如果测试邮件的这个单词在对应类别词汇表中
                        # 计算条件概率的对数
                        # 这里需要说明一下: +1是为了防止有些单词在测试样本中出现而垃圾邮件或正常邮件中没有导致概率为0 的情况
                        # 取log是为了防止概率太小 导致最后结果约等于0
                        log_probs[c] += math.log((self.word_given_class[c][word] + 1) / (self.word_total[c] + len(self.vocabulary)))  
            predictions.append(max(log_probs, key=log_probs.get))  # 取概率最大值对应的类别为预测结果

        return predictions

测试准确率

# 读取数据
X, y = get_data(DATA_DIR)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)  # 划分测试集和训练集

# 训练分类器
clf = NaiveBayesClassifier() # 实例化分类器
clf.fit(X_train, y_train)    # 送入数据训练
predictions = clf.predict(X_test)

#模型准确率
accuracy = np.sum(np.array(predictions) == np.array(y_test)) / len(y_test) # 计算准确率
print(f'Accuracy: {accuracy:.2f}')

预测新邮件

# 预测新邮件,并输出分类结果和准确率
new_email = 'Subject: et & s photo contest - announcing the winners\nCongratulations to the following winners of the 2001 ET & S photo contest. Over 200 entries were submitted! The winning photos will be displayed in the 2001 ET & S public education calendar.'
prediction = clf.predict([new_email])[0]
predictions = clf.predict(X_test)
accuracy = np.sum(np.array(predictions) == np.array(y_test)) / len(y_test)

print(f'Prediction: {target_names[prediction]}')
print(f'Accuracy: {accuracy:.2f}')

总代码

代码几乎每一行都加了注释,这里就不解释了。

import os
import re
import string
import math
import numpy as np
from collections import defaultdict
from sklearn.model_selection import train_test_split


DATA_DIR = 'enron'  # 数据集地址
target_names = ['ham', 'spam']  # 正常、 垃圾 
stopwords = set(open('stopwords.txt', 'r').read().splitlines())   # .splitlines() 按换行符分割


def get_data(DATA_DIR):
    subfolders = ['enron%d' % i for i in range(1,7)]  # 返回enron1-enron7列表
    data = []
    target = []
    for subfolder in subfolders: # 对enron1-enron7依次遍历
        # spam
        spam_files = os.listdir(os.path.join(DATA_DIR, subfolder, 'spam')) # 获文件夹下的所有文件 返回一个列表
        for spam_file in spam_files: # 依次打开返回的文件
            with open(os.path.join(DATA_DIR, subfolder, 'spam', spam_file), encoding="latin-1") as f:
                data.append(f.read())
                target.append(1)  # 垃圾邮件标签 为1
        # ham
        ham_files = os.listdir(os.path.join(DATA_DIR, subfolder, 'ham'))
        for ham_file in ham_files:
            with open(os.path.join(DATA_DIR, subfolder, 'ham', ham_file), encoding="latin-1") as f:
                data.append(f.read())
                target.append(0)  # 正常邮件标签 为0
    return data, target


def preprocess(text):
    """
    对文本进行处理,包括去除标点、转为小写、去除停用词等操作。
    """
    text = text.lower()  # 转为小写
    text = re.sub(f'[{string.punctuation}]', ' ', text)  # 去除标点符号
    text = [word for word in text.split() if word not in stopwords]  # 去除停用词
    return text


class NaiveBayesClassifier():
    def __init__(self):
        self.vocabulary = set()  # 词汇表
        self.class_total = defaultdict(int)  # 每个类别的文档数
        self.word_total = defaultdict(int)  # 每个类别中所有单词出现次数之和
        self.word_given_class = defaultdict(lambda: defaultdict(int))  # 每个类别中每个单词出现次数

    def fit(self, X, y):
        """
        训练分类器,其中 X 为训练集数据,y 为训练集标签。
        """
        for text, label in zip(X, y):
            words = preprocess(text)  # 对文本进行处理,包括去除标点、转为小写、去除停用词等操作。
            self.class_total[label] += 1   # 该类别文档数加1
            for word in words:             # 遍历每一个单词
                self.vocabulary.add(word)   # 加入词汇表
                self.word_given_class[label][word] += 1  # 该类别中该单词出现次数加1
                self.word_total[label] += 1  # 该类别所有单词出现次数之和加1

    def predict(self, X):
        """
        对新邮件进行分类,其中 X 为待分类邮件。
        """
        log_priors = {}  # 存储每个类别的先验概率的对数(用于避免下溢)
        for c in self.class_total.keys():
            #  log(每个类别的文档数/文档数)  也就是训练集正常邮件和垃圾邮件占总邮件的比例
            log_priors[c] = math.log(self.class_total[c] / sum(self.class_total.values())) 

        predictions = []
        for text in X:  # 遍历测试集的每一个邮件
            words = preprocess(text) # 对文本进行处理,包括去除标点、转为小写、去除停用词等操作。

            log_probs = {}
            for c in self.class_total.keys(): #遍历两个类别
                log_probs[c] = log_priors[c]
                for word in words:  # 遍历每个单词
                    if word in self.vocabulary:  # 如果测试邮件的这个单词在对应类别词汇表中
                        # 计算条件概率的对数
                        log_probs[c] += math.log((self.word_given_class[c][word] + 1) / (self.word_total[c] + len(self.vocabulary)))  
            predictions.append(max(log_probs, key=log_probs.get))  # 取概率最大值对应的类别为预测结果

        return predictions
# 预测新邮件,并输出分类结果和准确率
new_email = 'Subject: et & s photo contest - announcing the winners\nCongratulations to the following winners of the 2001 ET & S photo contest. Over 200 entries were submitted! The winning photos will be displayed in the 2001 ET & S public education calendar.'
prediction = clf.predict([new_email])[0]
predictions = clf.predict(X_test)
accuracy = np.sum(np.array(predictions) == np.array(y_test)) / len(y_test)

print(f'Prediction: {target_names[prediction]}')
print(f'Accuracy: {accuracy:.2f}')

数据集加工程文件

软件: anaconda python环境
链接:https://download.csdn.net/download/weixin_45464524/87689982


总结

终于水完了,,,

  • 17
    点赞
  • 125
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 42
    评论
### 回答1: 朴素贝叶斯分类器是一种常用的机器学习算法,可以用于分类问题。在Python中,可以使用scikit-learn库中的朴素贝叶斯分类器来预测垃圾邮件。具体步骤包括: 1. 收集和准备数据集:收集垃圾邮件和正常邮件的数据集,并将其转换为计算机可以处理的格式。 2. 特征提取:从邮件中提取特征,例如邮件的主题、发件人、正文等。 3. 数据预处理:对提取的特征进行预处理,例如去除停用词、词干提取等。 4. 训练模型:使用训练集训练朴素贝叶斯分类器模型。 5. 预测:使用测试集对模型进行测试,预测邮件是否为垃圾邮件。 6. 评估:评估模型的性能,例如准确率、召回率等。 通过以上步骤,可以使用Python中的朴素贝叶斯分类器来预测垃圾邮件。 ### 回答2: 朴素贝叶斯分类器是一种常见的机器学习算法,这个方法可以很好地处理文本分类问题,包括垃圾邮件的分类问题。Python中已经有了许多成熟的朴素贝叶斯分类器实现,例如scikit-learn、nltk等。 邮件分类涉及到以下过程: 1. 预处理:这个过程指的是将邮件转化为可供处理的数据格式,如文本形式或特征向量形式。 2. 特征提取:由于邮件是文本内容,所以我们需要从文本中提取有用的特征,例如单词的出现频率和词频等,这些特征可以反映文本的风格和主题,从而用于分类预测。 3. 模型训练:训练模型是指利用已知分类好的数据,通过朴素贝叶斯分类器构建一个分类预测模型,该模型可以将新出现的邮件根据训练好的模型进行分类预测。 4. 预测评估:最后,我们需要通过一些指标来评估我们所建立的模型的好坏,比如召回率,准确率等。 下面以Python中的scikit-learn库为例,介绍如何使用朴素贝叶斯分类器构建垃圾邮件分类器。 步骤一:首先需要加载数据集,一个常用的数据集是Enron-Spam数据集,该数据集有两种类型的邮件,一种是垃圾邮件,另一种是正常邮件。用Pandas库的read_csv函数可以用较为方便地加载该数据。 import pandas as pd data = pd.read_csv("spam.csv") 步骤二:将邮件文本转化为可供处理的特征向量形式。这里采用的是词袋模型,即将文本中的单词作为特征向量的每个维度,然后记录每个单词出现的频率。在Python中可以使用CountVectorizer函数来实现这个过程。 from sklearn.feature_extraction.text import CountVectorizer cv = CountVectorizer(stop_words="english") X = cv.fit_transform(data["text"]) 步骤三:划分样本集。为了进行分类模型的训练和测试,需要将数据集分成训练样本和测试样本。可以使用sklearn库中的train_test_split函数进行划分。 from sklearn.model_selection import train_test_split y = data["type"] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) 步骤四:训练朴素贝叶斯分类器模型。在Python中,可以使用MultinomialNB函数来训练模型。 from sklearn.naive_bayes import MultinomialNB nb = MultinomialNB() nb.fit(X_train, y_train) 步骤五:对测试集进行预测,通过查看模型在测试集上的表现,评估模型的分类效果。 y_pred = nb.predict(X_test) from sklearn.metrics import accuracy_score, classification_report, confusion_matrix print("Accurary:", accuracy_score(y_test, y_pred)) print("Confusion matrix:\n", confusion_matrix(y_test, y_pred)) print("Classification report:\n", classification_report(y_test, y_pred)) 预测结果可以通过模型的表现来观察,其中,准确率、混淆矩阵、分类报告都是评估模型性能的重要指标。 总的来说,朴素贝叶斯分类器是一种简单而有效的文本分类算法,特别适用于邮件分类场景。Python中有众多成熟的实现库,其中,scikit-learn是一种常用的实现库,通过以上五个步骤,我们可以使用Python构建一个高效的垃圾邮件分类器。 ### 回答3: 朴素贝叶斯分类器是一种机器学习算法,可以用来进行文本分类任务。在垃圾邮件分类任务中,我们可以使用朴素贝叶斯分类器来对邮件进行分类,判断其是垃圾邮件还是正常邮件。Python中有很多库可以用来实现朴素贝叶斯分类器,例如sklearn,nltk等等。 首先,我们需要准备数据集。可以使用已经标注好的数据集,例如SpamAssassin Public Corpus,也可以自己手动标注数据集。标注之后,将数据集分为训练集和测试集,通常将70%的数据作为训练集,30%的数据作为测试集。 接着,需要对文本进行预处理。预处理的步骤包括分词、去停用词、词干提取、统计词频等等。这些步骤可以使用nltk等自然语言处理工具库来实现。 接下来,我们可以使用sklearn库中的朴素贝叶斯分类器进行训练和预测。sklearn中有两种朴素贝叶斯分类器,分别是朴素贝叶斯分类器(MultinomialNB)和伯努利朴素贝叶斯分类器(BernoulliNB)。在垃圾邮件分类任务中,通常使用伯努利朴素贝叶斯分类器,因为该算法适合处理二元特征,即只考虑是否出现,而不考虑出现次数。 最后,我们可以使用测试集进行模型评估。常用的评估指标包括准确率、召回率、F1值等等。 总之,朴素贝叶斯分类器是一种高效的文本分类算法,可以用来预测垃圾邮件。在Python中,使用sklearn等库可以方便地实现朴素贝叶斯分类器,同时,预处理步骤也可以使用多种自然语言处理工具库来实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chaoy6565

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值