首页 > 其他分享 >L4 垃圾邮件数据集分类延申 - NB/KNN/SVC/随机森林

L4 垃圾邮件数据集分类延申 - NB/KNN/SVC/随机森林

时间:2024-11-15 14:44:03浏览次数:3  
标签:KNN score Text NB 延申 test import data 模型

目录

背景

代码

1. 数据准备-1阶段

2. 数据探索

3. 数据准备-2阶段

4. 矢量化(向量化)

5. 建立模型

6. 模型评价

模型评价

1. 分别评价

2. 总体评价


背景

基于前文 (《【机器学习】Lesson 4 - 朴素贝叶斯(NB)文本分类》)对于垃圾邮件数据集的分类处理,增加 K邻居分类器(KNN)/支持向量机(SVC)/随机森林 算法模型,并通过生成准确性报告和绘制混淆矩阵,对不同模型的性能进行比较。同时丰富数据预处理部分,增加词云展现等,完整代码及跑通效果见文档绑定资源。

本文在代码解释部分会跳过与前文雷同部分,详细可以在本文绑定资源中下载完整跑通源码查看。

代码

用大白话来讲的话,就是:

我们需要用着 5572 条邮件训练一个预测模型,以达到对邮件【是否】属于【垃圾邮件】进行预测分析。为了达到这一目的,我们选取的数据集是已经人为标注为非垃圾邮件("ham")和垃圾邮件("spam")过的。随后将数据分为一大半(训练集)和一小半(测试集),用训练集训练一个模型,然后用模型预测测试集,再用得到的结果与测试集已有标注进行比对,然后得到召回率、正确率等等评估模型性能的评分结果数据。

具体按照一定步骤如下:

1. 数据准备-1阶段

  1. 导包、导数据
  2. 预处理:即根据得到的数据集情况,删除多余的列、填补空值等等
  3. 数据转化:如果是中文标签的话,换成数字型,机器才看得懂。如本例中将 'spam' 转化为 1,'ham' 转化为 0。
## 数据处理类
import numpy as np 
import pandas as pd 
import warnings

## 数据可视化类
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
#from matplotlib.colors import ListedColormap #创建颜色映射表

import wordcloud
from wordcloud import WordCloud

## 自然语言处理类
import re #处理文本字符串,如查找、替换、分割和匹配
import nltk #文本预处理(如分词、词干提取、停用词过滤)、词性标注、命名实体识别、情感分析等各种自然语言处理任务
from nltk.corpus import stopwords #文本预处理
from nltk.tokenize import word_tokenize #分割文本
from nltk.stem.porter import PorterStemmer #词干提取算法
from nltk.stem import WordNetLemmatizer #去标点符号
from collections import Counter

from sklearn.preprocessing import MinMaxScaler,LabelEncoder 
# MinMaxScaler 能将类别型数据转换为数字
# LabelEncoder 进行特征放缩
from sklearn.feature_extraction.text import TfidfVectorizer #将原生文档转化为txt矩阵

## 分析算法类
from sklearn.naive_bayes import MultinomialNB #朴素贝叶斯
from sklearn.ensemble import RandomForestClassifier # 随机森林
from sklearn.neighbors import KNeighborsClassifier # KNN
from sklearn.svm import SVC # 支持向量机

## 算法优化类
from sklearn.pipeline import Pipeline #流水线操作
from sklearn.model_selection import GridSearchCV,cross_val_score,train_test_split 
# GridSearchCV 网格搜索,cross_val_score 交叉验证,train_test_split 数据划分

## 算法评分类
from sklearn import metrics
from sklearn.metrics import precision_score, recall_score, plot_confusion_matrix, classification_report, accuracy_score, f1_score


# 加载数据集
data = pd.read_csv("D:/project/Jupyter/csdn/AI_ML/datasets/Lesson4_SMS.csv")

data.info()


# 去除后面三列无意义列
to_drop = ["Unnamed: 2","Unnamed: 3","Unnamed: 4"]
data = data.drop(data[to_drop], axis=1)

# 重命名前两列 
data.rename(columns = {"v1":"Target", "v2":"Text"}, inplace = True)
data.head()

2. 数据探索

根据已有数据的情况,对数据进行一些统计探索,必要时可以进行数据可视化,使探索更加直观,根据展现出的情况对信息进行处理。

  1. 数据可视化:初步,从种类记数、高频词排序、占比等角度绘制图形。
  2. 特征工程:目的是最大限度地从原始数据中提取特征以供算法和模型使用。本例中将邮件内容按照字符数、词数、句子数,对文本内容进行拆分,并进行可视化碳素两两之间的数量关系。
  3. 异常值处理:此时出现一些明显不对劲的数据,为异常值,如下图红框部分,则需要根据其所在范围进行剔除,提高模型的准确性。

#first of all let us evaluate the target and find out if our data is imbalanced or not
plt.figure(figsize=(6,4))
fg = sns.countplot(x= data["Target"])
fg.set_title("Count Plot of Classes")
fg.set_xlabel("Classes")
fg.set_ylabel("Number of Data points")

## 词云
# 数据编码
data['spam'] = data['Target'].map( {'spam': 1, 'ham': 0} ).astype(int)
data.head(5)

# 提取出内容列的字符数
data["No_of_Characters"] = data["Text"].apply(len)

# 分离好坏类的短信,并以句子字符数为横轴绘图
data.hist(column='No_of_Characters', by='Target', bins=60, figsize=(12, 4))
plt.xlim(-40, 950)
plt.xlabel('Length')  # 设置横轴标签
plt.ylabel('Count')   # 设置纵轴标签

plt.show()data_ham  = data[data['spam'] == 0].copy()
data_spam = data[data['spam'] == 1].copy()

def show_wordcloud(data_spam_or_ham, title):
    Text = ' '.join(data_spam_or_ham['Text'].astype(str).tolist())
    stopwords = set(wordcloud.STOPWORDS)
    
    fig_wordcloud = wordcloud.WordCloud(stopwords=stopwords,background_color='lightgrey',
                    colormap='viridis', width=800, height=600).generate(Text)
    
    plt.figure(figsize=(10,7), frameon=True)
    plt.imshow(fig_wordcloud)  
    plt.axis('off')
    plt.title(title, fontsize=20 )
    plt.show()

show_wordcloud(data_ham, "Ham messages")

show_wordcloud(data_spam, "Spam messages")


## 特征工程
#添加列:字符数、单词数和句子数

# data["No_of_Characters"] = data["Text"].apply(len) 
# 字符数前面做词云的时候已经加了,遂注释掉

data["No_of_Words"]=data.apply(lambda row: nltk.word_tokenize(row["Text"]), axis=1).apply(len)
# 创建新列"No_of_Words",apply 将一个函数应用到 DataFrame 的每一行(axis=1),定义了一个匿名函数lambda接受行作为输入
# 使用 word_tokenize 函数对该行中的 Text 列进行分词,返回一个单词列表,使用 apply(len) 计算分词结果的长度,即单词的数量

data["No_of_sentence"]=data.apply(lambda row: nltk.sent_tokenize(row["Text"]), axis=1).apply(len)
# sent_tokenize 函数返回的是句子列表

data.describe().T # .T 是 DataFrame 的转置操作,将行和列互换

plt.figure(figsize=(12,8))
fg = sns.pairplot(data=data, hue="Target")
plt.show(fg)

3. 数据准备-2阶段

如果是数据型数据的话,这一步应该在第一步的数据准备里的,但是由于本篇代码属于自然语言处理,数据清洗需要放置于数据探索流程之后。其他的数据准备工作也相对来说复杂一些。

  1. 数据清洗:本例中,需要删除标点符号和数字,将所有字母改为小写。由于本篇目的为判断文本的属性,所以着重分析的是实词的感情色彩,数量含义可忽略。
  2. 文本分解:“token” 是指文本中的一个基本单位,文本通常需要转换成数字表示才能作为输入传递给算法进行处理。将文本句子分解为 token,方便后续将文本转换为数字化的向量,便于读取。
  3. 删除停用词:停用词是经常出现的单词(例如 Few、is、an 等)。这些词在句子结构中有意义,但对 NLP 中的语言处理贡献不大。为了消除处理中的冗余,需要将删除这些内容。标准选用 NLTK 库内的默认停用词组。
  4. 词形还原:词干提取是获取单词词根形式的过程。单词的词干是通过删除单词的前缀或后缀而创建的,词干提取会将其带回词根。词形还原还将单词转换为其词根形式。
# 查看数据
print("\033[1m\u001b[45;1m The First 5 Texts:\033[0m",*data["Text"][:5], sep = "\n")

# 编写数据清理函数
def Clean(Text):
    sms = re.sub('[^a-zA-Z]', ' ', Text) #Replacing all non-alphabetic characters with a space
    sms = sms.lower() #converting to lowecase
    sms = sms.split()
    sms = ' '.join(sms)
    return sms

data["Clean_Text"] = data["Text"].apply(Clean)

# 查看清理后数据
print("\033[1m\u001b[45;1m The First 5 Texts after cleaning:\033[0m",*data["Clean_Text"][:5], sep = "\n")

data["Tokenize_Text"]=data.apply(lambda row: nltk.word_tokenize(row["Clean_Text"]), axis=1)

print("\033[1m\u001b[45;1m The First 5 Texts after Tokenizing:\033[0m",*data["Tokenize_Text"][:5], sep = "\n")

# 删除停用词
def remove_stopwords(text):
    stop_words = set(stopwords.words("english"))
    filtered_text = [word for word in text if word not in stop_words]
    return filtered_text

data["Nostopword_Text"] = data["Tokenize_Text"].apply(remove_stopwords)

print("\033[1m\u001b[45;1m The First 5 Texts after removing the stopwords:\033[0m",*data["Nostopword_Text"][:5], sep = "\n")

lemmatizer = WordNetLemmatizer()

def lemmatize_word(text):
    #word_tokens = word_tokenize(text)
    # provide context i.e. part-of-speech
    lemmas = [lemmatizer.lemmatize(word, pos ='v') for word in text]
    return lemmas

data["Lemmatized_Text"] = data["Nostopword_Text"].apply(lemmatize_word)
print("\033[1m\u001b[45;1m The First 5 Texts after lemitization:\033[0m",*data["Lemmatized_Text"][:5], sep = "\n")

4. 矢量化(向量化)

在 NLP 中,清理后的数据需要转换为数字格式,其中每个单词都由一个矩阵表示。这也称为词嵌入或词向量化。

  1. 创建词形还原文本语料库
  2. 将语料库转换为向量形式
  3. 对 Target 中的类进行标签编码
#词频 (TF) = (文档中某个词的频率)/(文档中词的总数) 
#逆文档频率 (IDF) = log( (文档总数)/(包含词 t 的文档数) 
#I将使用 TfidfVectorizer() 对预处理后的数据进行矢量化。

#创建文本特征语料库
corpus= []
for i in data["Lemmatized_Text"]:
    msg = ' '.join([row for row in i])
    corpus.append(msg)
    
corpus[:5]
print("\033[1m\u001b[45;1m The First 5 lines in corpus :\033[0m",*corpus[:5], sep = "\n")

# 矢量化
tfidf = TfidfVectorizer()
X = tfidf.fit_transform(corpus).toarray()
# 查看特征
X.dtype

# 对目标进行标签编码并将其用作 y
label_encoder = LabelEncoder()
data["Target"] = label_encoder.fit_transform(data["Target"])

5. 建立模型

本文使用了 4 种不同的模型分别对数据集进行分类,均是从 sklearn 中提取的已经封装好的模型,故可以直接构建函数,实现分别训练和交叉验证,并得到正确率。

  1. 将特征和目标设置为 X 和 y,拆分测试集和训练集
  2. 为四个不同的分类构建模型:朴素贝叶斯(NB);K邻居分类器(KNN);支持向量机(SVC);随机森林
  3. 将所有模型拟合到训练数据集上
  4. 对所有模型的训练集进行交叉验证以确保准确性
y = data["Target"] 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 将他们投入不同分类模型
classifiers = [MultinomialNB(), 
               RandomForestClassifier(),
               KNeighborsClassifier(), 
               SVC()]
for cls in classifiers:
    cls.fit(X_train, y_train)

# 创建模型的对应字典,便于后续的函数读取
pipe_dict = {0: "NaiveBayes", 1: "RandomForest", 2: "KNeighbours",3: "SVC"}

# 交叉验证
for i, model in enumerate(classifiers):
    cv_score = cross_val_score(model, X_train,y_train,scoring="accuracy", cv=10)
    print("%s: %f " % (pipe_dict[i], cv_score.mean()))

6. 模型评价

对训练好的模型进行性能评估,以了解模型在未见过的新数据上的表现。本文中使用的评价方法为:生成准确性报告以及混淆矩阵。

  1. 准确性报告:列出表格,从 准确率、召回率、F1 分数、测试集准确率、训练集准确率 5个维度得出数据结论,便于一目了然地纵向对比。
  2. 混淆矩阵:比较模型时,TN和TP对角线两数值越大,FP和FN对角线两数值越小,模型性能越好。分类越准确混淆矩阵分为四块,分别为:
名称(位置)含义
TN(左上)非垃圾短信被正确地预测为非垃圾短信
FP(右上)非垃圾短信被错误地预测为垃圾短信(误报)
FN(左下)垃圾短信被错误地预测为非垃圾短信(漏报)
TP(右下)垃圾短信被正确地预测为垃圾短信
precision =[]
recall =[]
f1_score = []
trainset_accuracy = []
testset_accuracy = []

for i in classifiers:
    pred_train = i.predict(X_train)
    pred_test = i.predict(X_test)
    prec = metrics.precision_score(y_test, pred_test)
    recal = metrics.recall_score(y_test, pred_test)
    f1_s = metrics.f1_score(y_test, pred_test)
    train_accuracy = model.score(X_train,y_train)
    test_accuracy = model.score(X_test,y_test)
  
    #评分
    precision.append(prec)
    recall.append(recal)
    f1_score.append(f1_s)
    trainset_accuracy.append(train_accuracy)
    testset_accuracy.append(test_accuracy)

# 初始化一个列表
data = {'Precision':precision,
'Recall':recall,
'F1score':f1_score,
'Accuracy on Testset':testset_accuracy,
'Accuracy on Trainset':trainset_accuracy}
# 创建表格
Results = pd.DataFrame(data, index =["NaiveBayes", "RandomForest", "KNeighbours","SVC"])

#在同一图中绘制多个分类模型的混淆矩阵,以便比较分类模型的性能
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12,8))

for cls, ax in zip(classifiers, axes.flatten()):
    plot_confusion_matrix(cls, 
                          X_test, 
                          y_test, 
                          ax=ax
                          )
    ax.title.set_text(type(cls).__name__)
plt.tight_layout()  
plt.show()

模型评价

结合代码生成的准确性报告,以及混淆矩阵,对本文使用的四种模型进行评价分析。

1. 分别评价

  1. 朴素贝叶斯 (NB)

    • 准确率(Precision): 完美(1.0)。
    • Recall: 较低(0.705882),说明漏检率较高,有一定比例的垃圾短信未被识别(40个FN)。
    • F1 Score: 0.827586,主要是召回率拖累了整体分数,但是依然是较高的。
    • 总结: 适合不在意漏检的情况,适合需要更高精度的应用。
  2. 随机森林分类

    • 准确率(Precision): 完美(1.0)。
    • Recall: 较高(0.823529),FN较少(24个),说明对垃圾短信识别较好。
    • F1 Score: 0.903226,最高的F1分数,整体效果最佳。
    • 总结: 精确率和召回率平衡良好,适合对精度和召回率要求较高的任务。
  3. K 近邻分类 (KNN)

    • 准确率(Precision): 0.977778,相对最低,但是依然是很高的准确率。
    • Recall: 非常低(0.323529),FN较多(92个),说明漏检率非常高。
    • F1 Score: 0.486188,表现较差,尤其召回率影响较大。
    • 总结: 效果最差,不适合垃圾短信检测等需要较高召回率的任务。
  4. 支持向量机 (SVC)

    • 准确率(Precision): 0.990909,几乎完美。
    • Recall: 较高(0.801471),FN较少(27个),较好地识别了垃圾短信。
    • F1 Score: 0.886179,表现较为平衡,次于随机森林。
    • 总结: 效果不错,仅次于随机森林,在较高精度和召回率的情况下表现良好。

2. 总体评价

  • 最佳模型: 随机森林 (Random Forest),兼具高精度和高召回率。
  • 次优模型: SVC,次于随机森林,表现均衡。
  • 表现较差: KNN,由于召回率低导致漏检率高,不适合该场景。

标签:KNN,score,Text,NB,延申,test,import,data,模型
From: https://blog.csdn.net/lu_rong_qq/article/details/143575074

相关文章

  • OceanBase单表恢复(4.2.1.8)
    前言有一天正在查看社区的问题帖子,突然电话响起,开发人员反馈有一张业务表误操作被drop掉导致业务中断,询问单表是否可以恢复,当时安慰开发人员生产租户都存在备份,不要慌。我立刻登录OCP查看租户是否开启回收站以及租户的备份归档状态是否正常,此时手机不断弹出消息,开发人员已......
  • vscode + typora + picgo 搭建高效博客(cnblog)工作流
    vscode+typora+picgo搭建高效博客(cnblog)工作流笔者最初在cnblog上面发了很多随笔(水文),后面感觉广告有点多,并且难于管理文章,于是破罐破摔(不要学我)搭建了自己的博客。后来,我折腾过wordpress、jeklly、githubPages(hexo)和giteePages等等,既放不下cnblog上的流量与互动(......
  • 11.13机器学习_KNN和模型选择调优
    7特征降维实际数据中,有时候特征很多,会增加计算量,降维就是去掉一些特征,或者转化多个特征为少量个特征特征降维其目的:是减少数据集的维度,同时尽可能保留数据的重要信息。特征降维的好处:减少计算成本:在高维空间中处理数据可能非常耗时且计算密集。降维可以简化模型,......
  • 利用KNN对Iris鸢尾花数据集进行分类
    环境配置Python3.xScikit-learn库、Numpy库、Matplotlib库JupyterNotebook或类似IDE(用于代码编写和结果展示)数据集使用Scikit-learn自带的Iris数据集。该数据集包含150条记录,每条记录有4个特征(萼片长度、萼片宽度、花瓣长度、花瓣宽度),属于3个类别之一(Setosa、Versicolor......
  • 基于STM32设计的矿山环境监测系统(NBIOT)_262
    文章目录一、前言1.1项目介绍【1】开发背景【2】研究的意义【3】最终实现需求【4】项目硬件模块组成1.2设计思路【1】整体设计思路【2】上位机开发思路1.3项目开发背景【1】选题的意义【2】摘要【3】国内外相关研究现状【5】参考文献1.4......
  • 安川电源模块:YASKAWA CPS-IONB
    在开始安装CPS-IONB电源模块之前,应仔细阅读随附的安装手册,确保遵循正确的安装程序。安装过程主要包括以下步骤:选择合适位置:挑选通风良好、远离热源的位置,确保模块周围有足够的空间以便于散热和后续维护。固定模块:按照说明书指示,将模块牢固地安装在指定支架或机柜内。连......
  • 使用ob_tools包收集分析oceanbase数据库oracle租户缓慢sql语句
    概述1、手册目的:本手册旨在提供一种系统化的方法论,以便发现和分析慢SQL语句。通过使用ob_tools包,收集和分析在交付期间,应用程序在不同场景下进行压测时所产生的慢SQL语句,从而实现性能调优和优化建议。2、文档内容:本手册包含以下几个主要部分:1.ob_tools包内存储过程和函数介......
  • Queuing 表(buffer表)的优化实践 | OceanBase 性能优化实践
    案例问题描述该案例来自一个金融行业客户的问题:他们发现某个应用对一个数据量相对较小的表(仅包含数千条记录)访问时,频繁遇到性能下降的情况。为解决此问题,客户向我们求助进行分析。我们发现这张表有频繁的批量插入与删除操作,起初,性能基本正常,但不久后性能就会出现了下降。为深......
  • Excel.Application使用手册(摘自:https://www.cnblogs.com/codingking/p/6484461.html)
    定制模块行为(1)OptionExplicit'强制对模块内所有变量进行声明  OptionPrivateModule'标记模块为私有,仅对同一工程中其它模块有用,在宏对话框中不显示  OptionCompareText'字符串不区分大小写  OptionBase1'指定数组的第一个下标为1(2)OnErrorResumeNe......
  • 海力士 H9HCNNNBKUMLXR-NEE 在售中 ,Platinum P41 M.2 PCIE 4.0 2TB固态硬盘,Dram颗粒编
    主控:海力士ARIES主控(ACNS8075PMT762.00S-1)闪存:海力士SK4DV7176L(H25T3TCG8CX59),单颗容量为1TB,IO速率为1600MT/s缓存:海力士LPDDR4DDR4-426616Gb,容量为2048MB产品名称:海力士PlatinumP41SSD2TB闪存特写和缓存图片请参考相关资料。海力士PlatinumP41固态硬盘的性......