2.3 机器学习--朴素贝叶斯(分类)

news2024/10/26 6:50:05

本章我们来学习朴素贝叶斯算法,贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。而朴素贝叶斯分类是贝叶斯分类中最简单,也是常见的一种分类方法。

我们常常遇到这样的场景。与友人聊天时,一开始可能不知道他要说什么,但是他说了一句话之后,你就能猜到接下来他要讲什么内容。友人给的信息越多,我们越能够推断出他想表达的含义,这也是贝叶斯定理所阐述的思考方式。

在学习朴素贝叶斯之前,我们需要先了解一些概率基础。

目录

1.概率基础

2.算法原理

3. API 介绍

4.代码示例

4.1垃圾邮件过滤


1.概率基础

概率学是研究随机事件的一门学科,在概率学中0代表不可能事件,1代表必然事件,介于0和1之间的是概率事件。

在概率学中,事件 A 发生的概率的表现形式如下:

事件 A 不发生的概率表现如下:

假设有一个事件 B,事件 B 和事件 A 之间相互独立(也就是两者的结果相互之间是没有影响的),

即如果 A 和 B 相互独立,则有:

则事件 A 和 B 同时发生的概率表示如下:

对任意两个事件 A 和 B,计算事件 A 发生或事件 B 发生的概率如下(广义加法公式):

在已知 B 事件发生的条件下事件 A 发生的概率被称为条件概率,条件概率的计算公式如下:

将其变形,我们就得到了贝叶斯公式,如下:

这时候我们再来看贝叶斯定理,这个公式说明了两个互换的条件概率之间的关系,它们通过联合概率关联起来。在这种情况下,若知道P(A|B) 的值,就能够计算P(B|A)的值。

当有多个特征时,如果我们假设所有的特征之间相互独立,公式可以理解为:

换个表达形式就会明朗很多,如下:

我们举个例子来感受一下,现有两个类别的文章,分为科技类和娱乐类,统计了一下文章中的高频词汇,如下表格:

特征\统计科技(30篇)娱乐(60篇)汇总(90篇)
商场95160
影院85664
支付宝201535
云计算63063
汇总(求和)100121221

现有一篇被预测文档,出现了影院、支付宝、云计算词汇,计算属于科技、娱乐类别的概率:

所以这篇文章有 34% 的可能是科技类别,66% 的可能是娱乐类别,我们预测这篇文章属于娱乐类别。

2.算法原理

贝叶斯定理是英国学者贝叶斯在18世纪时提出的关于随机事件 A 和 B 的条件概率(或边缘概率)的一则定理。贝叶斯定理的表现形式如公式(4)中所示

现在我们来定义一个包含 n 个样本的数据集,这个数据集中的样本均可以被分到 k 种类别中:

则公式(2)可以被改写为如下形式:

在实际的计算过程中,P(x) 对于P(yk​∣x) 来说可以认为是一个常数(特征在数据集不变的情况下出现的概率是恒定的)。因此我们只需要令 P(yk​)P(x∣yk​) 取最大值就可以令 P(yk​∣x) 最大。

由于类别的先验概率 P(yk​) 通常是已知的,因此我们需要计算的就是似然P(x∣yk​)。在朴素贝叶斯中我们假定样本x 的各个属性相互独立,则可以用如下方式计算P(x∣yk​):

接下来的问题就是如何计算每个特征的条件概率P(xn​∣yk​)。首先假设属性Cn​ 是离散属性。训练集中属于类别 yk​ 的样本,在属性 Cn​ 下的相异属性共有n个;训练集中属于类别 yk​,且在属性 Cn​ 下的属性值为 xn​ 的样本共有m个,则 P(xn​∣yk​) 的计算方式如下:

接下来我们假设属性 Cn​ 是连续属性。这里我们认为这个连续属性服从均值为 μ 、标准差为 σ 的高斯分步(正态分布):

在高斯分布下,条件概率 P(xn​∣yk​) 的计算方式如下:

其中,μyk​​,σyk​​ 表示训练集中属于类别yk​ 的样本在属性 Cn​ 下的均值和标准差

从上面的计算可以看出,没有复杂的求导和矩阵运算,因此效率很高。

3. API 介绍

sklearn 朴素贝叶斯分类算法 API:

1sklearn.naive_bayes.MultinomialNB(alpha=1.0)
  • alpha: 拉普拉斯平滑系数

为了解决零概率的问题,法国数学家拉普拉斯最早提出用加1的方法估计没有出现过的现象的概率,所以加法平滑也叫做拉普拉斯平滑。假定训练样本很大时,每个分量x的计数加1造成的估计概率变化可以忽略不计,但可以方便有效的避免零概率问题。

避免每一项为零的做法就是, 在分子、 分母上各加一个数值。

算法优点:

(1)朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。

(2)对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练。

(3)对缺失数据不太敏感,算法也比较简单,常用于文本分类。

算法缺点:

(1) 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。

(2)需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。

(3)由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。

(4)对输入数据的表达形式很敏感。


4.代码示例

4.1垃圾邮件过滤

         TF-IDF是一种用于信息检索与文本挖掘的常用加权技术。

         TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

         TF-IDF的主要思想是:如果某个单词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。

TF是词频(Term Frequency) 词频(TF)表示词条(关键字)在文本中出现的频率。 这个数字通常会被归一化(一般是词频除以文章总词数), 以防止它偏向长的文件。

数据集:SMSSpam.txt

//数据集太大了,csdn下载文件好像要vip,需要的call:13438784965

1.导入包 

#1.导入包
import numpy as np
import os
import re
import sklearn
import matplotlib.pyplot as plt
import pandas as pd
import string
from sklearn.feature_extraction.text import TfidfVectorizer as TFIDF
from sklearn.calibration import CalibratedClassifierCV
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB
import sklearn.model_selection as sk_model_selection

import nltk
from nltk.corpus import stopwords

2.切片和清理文本


#2.切分和清理文本
def Text_process(text,stem=True):
    #人造特征(网址+电话)
    man_made_features = [0,0]
    # 初始化一个名为man_made_features的列表,包含两个元素,分别用于表示文本中是否包含网址和电话号码。初始值都设为0(表示不存在)。

    #是否有网址
    pattern = re.compile(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+')
    # 使用re模块的compile函数编译一个正则表达式,用于匹配网址。
    # 正则表达式解释:
    # r'http[s]?:// 匹配字符串"http://"或"https://"
    # (?: ...) 是一个非捕获组,用于分组但不保存匹配结果
    # [a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),] 匹配字母、数字、特定符号
    # (?:%[0-9a-fA-F][0-9a-fA-F]) 匹配URL中的百分比编码(例如%20代表空格)
    # + 表示前面的字符集可以出现一次或多次

    if re.findall(pattern,text):
        man_made_features[0]=1
    # 使用re.findall函数查找所有匹配正则表达式的子串,如果找到匹配项,将man_made_features列表的第一个元素设置为1,表示文本包含网址。

    #是否有电话
    if re.findall(r'[0-9]{4,}',text):
        man_made_features[1]=1
    # 使用re.findall函数查找所有至少包含4个数字的子串,如果找到匹配项,将man_made_features列表的第二个元素设置为1,表示文本包含电话号码。
    # 正则表达式解释:
    # [0-9]{4,} 匹配至少连续4个数字

    #去除缩写"'m","'re","'s"替换部分缩写
    short = ["'m","'re","'s","'ve",' c u ',"n't",' u ']
    repla = ['am', 'are', 'is', 'have', ' see you ', ' not', ' you ']
    # 定义两个列表,short包含需要替换的缩写,repla包含相应的替换文本。

    for i,w in enumerate(short):
        text=text.replace(w,repla[i])
    # 遍历short列表,使用字符串的replace方法将每个缩写替换为对应的完整形式。

    #去除标点
    remove = str.maketrans('','',string.punctuation)
    text = text.translate(remove)
    # 使用str.maketrans创建一个转换表,用于删除所有标点符号,然后使用translate方法去除文本中的所有标点符号。

    #分词
    tokens = text.split()
    # 使用split方法将文本分割成单词列表(分词)。

    #去停用词(代码被注释掉了)
    # doc = [w for w in tokens if not w in stopwords.words('english')]
    doc = tokens
    # 将分词后的结果赋值给变量doc,注意:这里注释掉了去停用词的代码。

    #词干提取(默认开启)
    if stem:
        s = nltk.stem.SnowballStemmer('english')
        doc = [s.stem(ws) for ws in doc]
    # 如果stem参数为True,则创建一个SnowballStemmer对象用于英语词干提取,并使用列表推导式对doc中的每个单词进行词干提取。

    result = ' '.join(doc)
    # 使用join方法将处理后的单词列表doc连接成一个字符串,存储在result变量中。

    return man_made_features,result
    # 返回一个元组,包含man_made_features列表和result字符串,表示人造特征和处理后的文本。


def File_process(filename, stem=True):
    # 初始化三个列表,分别用于存储邮件的标签、特征和内容
    labels = []  # 存储邮件标签(通常是垃圾邮件或非垃圾邮件的标识)
    features = []  # 存储邮件的特征,这些特征可能是从文本中提取的
    contents = []  # 存储邮件的原始内容

    # 使用with语句打开文件,确保文件在操作完成后会被正确关闭
    with open(filename, 'r', encoding='utf-8') as f:
        # 读取文件中的所有行,并存储在lines列表中
        lines = f.readlines()

        # 初始化一个计数器i,但在后续代码中并未使用,可能是用于调试或其他目的
        i = 0

        # 遍历文件中的每一行
        for line in lines:
            # 使用制表符('\t')分割每行,得到标签和数据
            target = line.split('\t')

            # 将分割后的第一部分(target[0])作为标签,如果标签是'ham'则设为1,否则设为0
            label = 1 if target[0] == 'ham' else 0

            # 调用Text_process函数处理邮件内容,可能包括文本处理和特征提取
            # target[1]是邮件内容,.lower()将其转换为小写,stem参数用于控制是否进行词干提取
            feature, content = Text_process(target[1].lower(), stem)

            # 将处理后的标签、特征和内容分别添加到对应的列表中
            labels.append(label)
            features.append(feature)
            contents.append(content)

            # 以下代码被注释掉了,如果启用,它将检查内容是否非空,然后添加到列表中
            # 但由于之前的代码已经添加了内容,这部分代码是多余的
            # if len(content):
            #     labels.append(label)
            #     features.append(feature)
            #     contents.append(content)

    # 函数返回三个列表:邮件内容、特征和标签
    return contents, features, labels

3.TFIDF构建数据集


#3.利用TFIDF构造训练集
def TF_IDF(contents):
    # 定义一个函数TF_IDF,它接收一个参数contents,即文本内容列表。

    vec = TFIDF(
        min_df=3,              # 最小文档频率,忽略文档频率低于3的特征词。
        max_features=None,     # 最多使用的特征数量,None表示无限制。
        strip_accents='unicode', # 移除字符的变音符号,'unicode'表示使用Unicode编码的规则。
        analyzer='word',       # 指定分词方式,'word'表示按单词进行分词。
        token_pattern=r'\w{1,}', # 正则表达式模式,用于识别单词,'\w{1,}'表示匹配一个或多个字母数字字符。
        ngram_range=(1, 1),    # 设置n-gram的上下界,(1, 1)表示只考虑单个单词(unigrams)。
        use_idf=True,             # 启用逆文档频率权重。
        smooth_idf=True,          # 平滑IDF权重,防止除以零。
        sublinear_tf=True,        # 应用子线性TF缩放,即用1 + log(tf)代替tf。
        stop_words='english'   # 使用英语停用词列表,'english'表示使用内置的英语停用词。
    )
    # 创建一个TF-IDF向量化器实例vec,并设置其参数。

    X = vec.fit_transform(contents)
    # 使用向量化器vec拟合并转换文本内容列表contents,得到TF-IDF矩阵X。

    result = pd.DataFrame(X.toarray(), columns=vec.get_feature_names_out())
    # 将TF-IDF矩阵X转换为DataFrame格式,列名为特征词,并赋值给变量result。

    print("shape of data:", result.shape)
    # 打印出数据的形状,即矩阵的行数和列数。`

    return result, vec
    # 返回两个值:TF-IDF矩阵的DataFrame表示result和拟合后的向量化器实例vec。
contents,features,labels=File_process("C:\pythonProject\机器学习\分类算法\朴素贝叶斯\SMSSpam.txt",False)#不提取词干,可能要等一会
"""
os.path.join('data', 'data19334', 'SMSSpam.txt'):这个表达式使用了os.path.join函数来构造一个跨平台的文件路径。它会将字符串参数连接起来形成一个完整的路径,这里指的是data/data19334/SMSSpam.txt。
False:这是一个布尔值,作为第二个参数传递给File_process函数。根据您之前提供的Fileprocess函数(注意大小写差异),这个布尔值可能用于控制是否进行词干提取(stemming)。在这里,False表示不进行词干提取。
File_process:这是一个函数调用,它应该定义在您的代码中的某个地方,并且负责处理文件。您提供的参数是文件的路径和布尔值。函数的预期行为是读取指定的文件,并返回三个列表:contents(邮件内容)、features(特征)和labels(标签)。
contents, features, labels = ...:这是一个赋值语句,它将File_process函数返回的三个值分别赋给contents、features和labels这三个变量。
"""
print(contents[:5]) #前五条数据
print(len(contents)) #数据集长度

X_1, vec = TF_IDF(contents)  # 将邮件内容转换为TF-IDF矩阵,X_1是无人造特征的训练集,vec是转换工具。
F = pd.DataFrame(features, columns=['网址', '电话'])  # 将人造特征列表转换为DataFrame,列名为'网址'和'电话'。
X_2 = pd.concat([F, X_1], axis=1)  # 将人造特征DataFrame与TF-IDF矩阵横向合并,形成完整的特征集X_2。
Y = pd.DataFrame(labels, columns=['labels'])  # 将标签列表转换为DataFrame,列名为'labels'。

print(Y.head(5))
print("无人造特征:",X_1.shape)
print("有人造特征:",X_2.shape)

baseline = sum(labels)/len(labels) #0.866 非垃圾邮件占所有邮件的 86.6%,只有结果超过 86.6%,模型才有意义
print("非垃圾邮件占比:"+str(baseline))

4. 训练模型

#4.模型训练
#最高分:不提取词干+人造特征(网址+电话)+补集朴素贝叶斯+sigmid校准 准确率: 0.9872643820427529
#10折交叉验证
CV = 10 #交叉验证次数,嫌弃速度慢可以改小
names = ["LR"
        ,"LR + Isotonic"
        ,"LR + Sigmoid"
        ,"Naive Bayes"
        ]

# 各类模型
models = [
        # LR
        LogisticRegression()
        # LR + Isotonic
        ,CalibratedClassifierCV(LogisticRegression(), cv=2, method='isotonic')
        # LR + Sigmoid
        ,CalibratedClassifierCV(LogisticRegression(), cv=2, method='sigmoid')
        # Naive Bayes
        ,MultinomialNB()
         ]

print("无人造特征")
for name,model in zip(names,models):  # 遍历names和models两个列表,将每个元素配对给name和model变量。
    accs = sum(sk_model_selection.cross_val_score(model, X_1, y=Y.values.ravel(), cv=10, n_jobs=-1)) / 10
    """
    sk_model_selection.cross_val_score: 这是scikit-learn库中的一个函数,用于执行交叉验证并返回每次验证的得分。
model: 这是您要评估的模型对象。在交叉验证过程中,这个模型将被训练并评估多次。
X_1: 这是您的特征数据集,用于训练模型。
y=Y: 这是您的目标变量(标签),用于评估模型的性能。,y=Y.values.ravel(): 这是将标签转换为一维数组的一种方式。
cv=10: 这指定了交叉验证的折数,在这里是10折交叉验证。这意味着数据集将被分成10个不同的部分,每个部分轮流作为验证集,其余部分作为训练集。
n_jobs=-1: 这个参数告诉函数使用所有可用的CPU核心来并行计算。这可以显著加快交叉验证的过程。
sum(...): 这个函数将交叉验证的所有得分相加。
/ 10: 最后,将总得分除以折数(10),以得到平均得分。
"""

    # 对每个模型执行10折交叉验证,计算平均准确率,并将结果赋值给accs。
                                                #,scoring='roc_auc'

    print(name, '交叉验证结果:', accs)  # 打印每个模型的名称和其交叉验证的平均准确率结果。


print("有人造特征")
for name,model in zip(names,models):
    accs=sum(sk_model_selection.cross_val_score(model, X_2, y=Y.values.ravel(),cv=CV, n_jobs=-1
                                                #,scoring='roc_auc'
                                                ))/10
    print(name,'交叉验证结果:',accs)

完整代码:

#1.导入包
import numpy as np
import os
import re
import sklearn
import matplotlib.pyplot as plt
import pandas as pd
import string
from sklearn.feature_extraction.text import TfidfVectorizer as TFIDF
from sklearn.calibration import CalibratedClassifierCV
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB
import sklearn.model_selection as sk_model_selection

import nltk
from nltk.corpus import stopwords


#2.切分和清理文本
def Text_process(text,stem=True):
    #人造特征(网址+电话)
    man_made_features = [0,0]
    # 初始化一个名为man_made_features的列表,包含两个元素,分别用于表示文本中是否包含网址和电话号码。初始值都设为0(表示不存在)。

    #是否有网址
    pattern = re.compile(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+')
    # 使用re模块的compile函数编译一个正则表达式,用于匹配网址。
    # 正则表达式解释:
    # r'http[s]?:// 匹配字符串"http://"或"https://"
    # (?: ...) 是一个非捕获组,用于分组但不保存匹配结果
    # [a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),] 匹配字母、数字、特定符号
    # (?:%[0-9a-fA-F][0-9a-fA-F]) 匹配URL中的百分比编码(例如%20代表空格)
    # + 表示前面的字符集可以出现一次或多次

    if re.findall(pattern,text):
        man_made_features[0]=1
    # 使用re.findall函数查找所有匹配正则表达式的子串,如果找到匹配项,将man_made_features列表的第一个元素设置为1,表示文本包含网址。

    #是否有电话
    if re.findall(r'[0-9]{4,}',text):
        man_made_features[1]=1
    # 使用re.findall函数查找所有至少包含4个数字的子串,如果找到匹配项,将man_made_features列表的第二个元素设置为1,表示文本包含电话号码。
    # 正则表达式解释:
    # [0-9]{4,} 匹配至少连续4个数字

    #去除缩写"'m","'re","'s"替换部分缩写
    short = ["'m","'re","'s","'ve",' c u ',"n't",' u ']
    repla = ['am', 'are', 'is', 'have', ' see you ', ' not', ' you ']
    # 定义两个列表,short包含需要替换的缩写,repla包含相应的替换文本。

    for i,w in enumerate(short):
        text=text.replace(w,repla[i])
    # 遍历short列表,使用字符串的replace方法将每个缩写替换为对应的完整形式。

    #去除标点
    remove = str.maketrans('','',string.punctuation)
    text = text.translate(remove)
    # 使用str.maketrans创建一个转换表,用于删除所有标点符号,然后使用translate方法去除文本中的所有标点符号。

    #分词
    tokens = text.split()
    # 使用split方法将文本分割成单词列表(分词)。

    #去停用词(代码被注释掉了)
    # doc = [w for w in tokens if not w in stopwords.words('english')]
    doc = tokens
    # 将分词后的结果赋值给变量doc,注意:这里注释掉了去停用词的代码。

    #词干提取(默认开启)
    if stem:
        s = nltk.stem.SnowballStemmer('english')
        doc = [s.stem(ws) for ws in doc]
    # 如果stem参数为True,则创建一个SnowballStemmer对象用于英语词干提取,并使用列表推导式对doc中的每个单词进行词干提取。

    result = ' '.join(doc)
    # 使用join方法将处理后的单词列表doc连接成一个字符串,存储在result变量中。

    return man_made_features,result
    # 返回一个元组,包含man_made_features列表和result字符串,表示人造特征和处理后的文本。


def File_process(filename, stem=True):
    # 初始化三个列表,分别用于存储邮件的标签、特征和内容
    labels = []  # 存储邮件标签(通常是垃圾邮件或非垃圾邮件的标识)
    features = []  # 存储邮件的特征,这些特征可能是从文本中提取的
    contents = []  # 存储邮件的原始内容

    # 使用with语句打开文件,确保文件在操作完成后会被正确关闭
    with open(filename, 'r', encoding='utf-8') as f:
        # 读取文件中的所有行,并存储在lines列表中
        lines = f.readlines()

        # 初始化一个计数器i,但在后续代码中并未使用,可能是用于调试或其他目的
        i = 0

        # 遍历文件中的每一行
        for line in lines:
            # 使用制表符('\t')分割每行,得到标签和数据
            target = line.split('\t')

            # 将分割后的第一部分(target[0])作为标签,如果标签是'ham'则设为1,否则设为0
            label = 1 if target[0] == 'ham' else 0

            # 调用Text_process函数处理邮件内容,可能包括文本处理和特征提取
            # target[1]是邮件内容,.lower()将其转换为小写,stem参数用于控制是否进行词干提取
            feature, content = Text_process(target[1].lower(), stem)

            # 将处理后的标签、特征和内容分别添加到对应的列表中
            labels.append(label)
            features.append(feature)
            contents.append(content)

            # 以下代码被注释掉了,如果启用,它将检查内容是否非空,然后添加到列表中
            # 但由于之前的代码已经添加了内容,这部分代码是多余的
            # if len(content):
            #     labels.append(label)
            #     features.append(feature)
            #     contents.append(content)

    # 函数返回三个列表:邮件内容、特征和标签
    return contents, features, labels

#3.利用TFIDF构造训练集
def TF_IDF(contents):
    # 定义一个函数TF_IDF,它接收一个参数contents,即文本内容列表。

    vec = TFIDF(
        min_df=3,              # 最小文档频率,忽略文档频率低于3的特征词。
        max_features=None,     # 最多使用的特征数量,None表示无限制。
        strip_accents='unicode', # 移除字符的变音符号,'unicode'表示使用Unicode编码的规则。
        analyzer='word',       # 指定分词方式,'word'表示按单词进行分词。
        token_pattern=r'\w{1,}', # 正则表达式模式,用于识别单词,'\w{1,}'表示匹配一个或多个字母数字字符。
        ngram_range=(1, 1),    # 设置n-gram的上下界,(1, 1)表示只考虑单个单词(unigrams)。
        use_idf=True,             # 启用逆文档频率权重。
        smooth_idf=True,          # 平滑IDF权重,防止除以零。
        sublinear_tf=True,        # 应用子线性TF缩放,即用1 + log(tf)代替tf。
        stop_words='english'   # 使用英语停用词列表,'english'表示使用内置的英语停用词。
    )
    # 创建一个TF-IDF向量化器实例vec,并设置其参数。

    X = vec.fit_transform(contents)
    # 使用向量化器vec拟合并转换文本内容列表contents,得到TF-IDF矩阵X。

    result = pd.DataFrame(X.toarray(), columns=vec.get_feature_names_out())
    # 将TF-IDF矩阵X转换为DataFrame格式,列名为特征词,并赋值给变量result。

    print("shape of data:", result.shape)
    # 打印出数据的形状,即矩阵的行数和列数。`

    return result, vec
    # 返回两个值:TF-IDF矩阵的DataFrame表示result和拟合后的向量化器实例vec。
contents,features,labels=File_process("/机器学习/分类算法/朴素贝叶斯/SMSSpam-gyp.txt", False)#不提取词干,可能要等一会
"""
os.path.join('data', 'data19334', 'SMSSpam-gyp.txt'):这个表达式使用了os.path.join函数来构造一个跨平台的文件路径。它会将字符串参数连接起来形成一个完整的路径,这里指的是data/data19334/SMSSpam-gyp.txt。
False:这是一个布尔值,作为第二个参数传递给File_process函数。根据您之前提供的Fileprocess函数(注意大小写差异),这个布尔值可能用于控制是否进行词干提取(stemming)。在这里,False表示不进行词干提取。
File_process:这是一个函数调用,它应该定义在您的代码中的某个地方,并且负责处理文件。您提供的参数是文件的路径和布尔值。函数的预期行为是读取指定的文件,并返回三个列表:contents(邮件内容)、features(特征)和labels(标签)。
contents, features, labels = ...:这是一个赋值语句,它将File_process函数返回的三个值分别赋给contents、features和labels这三个变量。
"""
print(contents[:5]) #前五条数据
print(len(contents)) #数据集长度

X_1, vec = TF_IDF(contents)  # 将邮件内容转换为TF-IDF矩阵,X_1是无人造特征的训练集,vec是转换工具。
F = pd.DataFrame(features, columns=['网址', '电话'])  # 将人造特征列表转换为DataFrame,列名为'网址'和'电话'。
X_2 = pd.concat([F, X_1], axis=1)  # 将人造特征DataFrame与TF-IDF矩阵横向合并,形成完整的特征集X_2。
Y = pd.DataFrame(labels, columns=['labels'])  # 将标签列表转换为DataFrame,列名为'labels'。

print(Y.head(5))
print("无人造特征:",X_1.shape)
print("有人造特征:",X_2.shape)

baseline = sum(labels)/len(labels) #0.866 非垃圾邮件占所有邮件的 86.6%,只有结果超过 86.6%,模型才有意义
print("非垃圾邮件占比:"+str(baseline))


#4.模型训练
#最高分:不提取词干+人造特征(网址+电话)+补集朴素贝叶斯+sigmid校准 准确率: 0.9872643820427529
#10折交叉验证
CV = 10 #交叉验证次数,嫌弃速度慢可以改小
names = ["LR"
        ,"LR + Isotonic"
        ,"LR + Sigmoid"
        ,"Naive Bayes"
        ]

# 各类模型
models = [
        # LR
        LogisticRegression()
        # LR + Isotonic
        ,CalibratedClassifierCV(LogisticRegression(), cv=2, method='isotonic')
        # LR + Sigmoid
        ,CalibratedClassifierCV(LogisticRegression(), cv=2, method='sigmoid')
        # Naive Bayes
        ,MultinomialNB()
         ]

print("无人造特征")
for name,model in zip(names,models):  # 遍历names和models两个列表,将每个元素配对给name和model变量。
    accs = sum(sk_model_selection.cross_val_score(model, X_1, y=Y.values.ravel(), cv=10, n_jobs=-1)) / 10
    """
    sk_model_selection.cross_val_score: 这是scikit-learn库中的一个函数,用于执行交叉验证并返回每次验证的得分。
model: 这是您要评估的模型对象。在交叉验证过程中,这个模型将被训练并评估多次。
X_1: 这是您的特征数据集,用于训练模型。
y=Y: 这是您的目标变量(标签),用于评估模型的性能。,y=Y.values.ravel(): 这是将标签转换为一维数组的一种方式。
cv=10: 这指定了交叉验证的折数,在这里是10折交叉验证。这意味着数据集将被分成10个不同的部分,每个部分轮流作为验证集,其余部分作为训练集。
n_jobs=-1: 这个参数告诉函数使用所有可用的CPU核心来并行计算。这可以显著加快交叉验证的过程。
sum(...): 这个函数将交叉验证的所有得分相加。
/ 10: 最后,将总得分除以折数(10),以得到平均得分。
"""

    # 对每个模型执行10折交叉验证,计算平均准确率,并将结果赋值给accs。
                                                #,scoring='roc_auc'

    print(name, '交叉验证结果:', accs)  # 打印每个模型的名称和其交叉验证的平均准确率结果。


print("有人造特征")
for name,model in zip(names,models):
    accs=sum(sk_model_selection.cross_val_score(model, X_2, y=Y.values.ravel(),cv=CV, n_jobs=-1
                                                #,scoring='roc_auc'
                                                ))/10
    print(name,'交叉验证结果:',accs)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

合合信息亮相2024中国模式识别与计算机视觉大会,用AI构建图像内容安全防线

近日,第七届中国模式识别与计算机视觉大会(简称“PRCV 2024”)在乌鲁木齐举办。大会由中国自动化学会(CAA)、中国图象图形学学会(CSIG)、中国人工智能学会(CAAI)和中国计…

分享几个办公类常用的AI工具

办公类 WPS AI讯飞智文iSlideProcessOn亿图脑图ChatPPT WPS AI 金山办公推出的协同办公 AI 应用,具有文本生成、多轮对话、润色改写等多种功能,可以辅助用户进行文档编辑、表格处理、演示文稿制作等办公操作。 https://ai.wps.cn/ 讯飞智文 科大讯飞推…

我谈Canny算子

在Canny算子的论文中,提出了好的边缘检测算子应满足三点:①检测错误率低——尽可能多地查找出图像中的实际边缘,边缘的误检率(将边缘识别为非边缘)低,且避免噪声产生虚假边缘(将非边缘识别为边缘…

高效文本编辑与导航:Vim中的三种基本模式及粘滞位的深度解析

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

有色行业测温取样机器人 - SNK施努卡

SNK施努卡有色行业熔炼车间机器人测温取样 在有色行业,测温取样机器人专门设计用于自动化处理高温熔体的温度监测和样品采集任务。这类机器人在铜、铝、锌等金属冶炼过程中扮演着关键角色,以提高生产效率、确保产品质量并增强工作安全性。 主要工作项 …

ABAP ALV

目录 一、基本概念 1、ALV概览 2、基本概念 二、属性更改 1、FIELDCAT 2、宏 3、LAYOUT 4、升序降序SORT 5、FILTER 三、交互 1、实现自己的按钮 一、基本概念 1、ALV概览 ALV:SAP List View,是SAP提供的一个强大的数据报表显示工具 ALV实际上是一个…

前端零基础入门到上班:【Day3】从零开始构建网页骨架HTML

HTML 基础入门&#xff1a;从零开始构建网页骨架 目录 1. 什么是 HTML&#xff1f;HTML 的核心作用 2. HTML 基本结构2.1 DOCTYPE 声明2.2 <html> 标签2.3 <head> 标签2.4 <body> 标签 3. HTML 常用标签详解3.1 标题标签3.2 段落和文本标签3.3 链接标签3.4 图…

CRLF、UTF-8这些编辑器右下角的选项的意思

经常使用编辑器的小伙伴应该经常能看到右下角会有这么两个选项&#xff0c;下图是VScode中的示例&#xff0c;那么这两个到底是啥作用呢&#xff1f; 目录 字符编码ASCII 字符集GBK 字符集Unicode 字符集UTF-8 编码 换行 字符编码 此部分参考博文 在计算机中&#xff0c;所有…

网络搜索引擎Shodan(1)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shodan(1)_哔哩哔哩_bilibili 本文主要讲解网络搜索引擎Shodan的一些用法&#xff08;host和search这两个命令&#xff09;。 Shodan 是一个网络…

合合信息亮相PRCV大会,探讨生成式AI时代的内容安全与系统构建加速

一、前言 在人工智能技术的飞速发展下&#xff0c;生成式AI已经成为推动社会进步的重要力量。然而&#xff0c;随着技术的不断进步&#xff0c;内容安全问题也日益凸显。如何确保在享受AI带来的便利的同时&#xff0c;保障信息的真实性和安全性&#xff0c;已经成为整个行业待解…

高速自爆穿梭无人机技术详解

高速自爆穿梭无人机技术是一种结合了高速飞行与自爆式攻击能力的先进无人机技术。以下是对该技术的详细解析&#xff1a; 一、技术特点 1. 高速飞行&#xff1a; 高速自爆穿梭无人机通常具备极高的飞行速度&#xff0c;如部分型号的速度可达到174公里/小时&#xff0c;甚至更…

Stack和Queue(3)

Stack和Queue&#xff08;3&#xff09; priority_queue的模拟实现 priority_queue.h #include <vector>namespace soobin {template<class T, class Container vector<T>>class priority_queue{public://强制生成默认构造priority_queue() default;temp…

html+css+js实现Notification 通知

实现效果&#xff1a; 代码实现&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Notif…

深入拆解TomcatJetty——Tomcat如何实现IO多路复用

深入拆解Tomcat&Jetty 专栏地址&#xff1a; 极客时间-深入拆解Tomcat & Jetty IO 多路复用 当用户线程发起 I/O 操作后&#xff0c;网络数据读取操作会经历两个步骤&#xff1a; 用户线程等待内核将数据从网卡拷贝到内核空间。内核将数据从内核空间拷贝到用户空间…

Docker搭建DVWA靶场以及刷题记录

Docker搭建DVWA靶场以及刷题记录 Docker搭建DVWA靶场以及刷题记录靶场搭建 刷题记录SQL InjectionLowMediumHighImpossible SQL Injection(Blind)LowMediumHigh XSS (Reflected)LowMediumHigh XSS (Stored)LowMediumHigh File UploadLowMediumHigh Docker搭建DVWA靶场以及刷题记…

zabbix 6.0 监控clickhouse(单机)

zabbix 6.0 LTS已经包含了clickhouse的监控模板&#xff0c;所以我们可以直接使用自带的模板来监控clickhouse了。 0.前置条件 clickhouse 已经安装&#xff0c;我安装的是24.3.5.47zabbix-agent 已经安装并配置。系统是ubuntu 2204 server 1. 新建监控用户 使用xml的方式为…

适用于 Windows 11/10 电脑 的 13 个最佳文件恢复软件

如果您由于系统故障、硬件损坏、人为错误或病毒攻击而丢失了重要文件或文件夹。不用担心&#xff0c;因为我们随时为您提供帮助&#xff01;借助正确的文件恢复工具&#xff0c;您可以立即检索计算机上不同类型的文件。如果你有为您的文件创建备份&#xff0c;你不用担心&#…

juzigei/基于 ThinkPHP+Mysql灵活用工_灵活用工系统_灵活用工平台

基于 ThinkPHPMysql 灵活用工灵活用工平台灵活用工系统灵活用工小程序灵活用工源码灵活用工系统源码 开发语言 ThinkPHPMysql 源码合作 提供完整源代码 软件界面展示 一、企业管理后台 二、运用管理平台 三、手机端

ECharts饼图-饼图自定义样式,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个饼图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供详…

视频播放速度过快怎么办?视频速度调慢的简单方法

视频播放速度过快怎么办&#xff1f;在这个快节奏的时代&#xff0c;我们似乎习惯了迅速浏览和消化信息&#xff0c;视频内容也不例外。然而&#xff0c;有时我们会遇到视频速度过快的问题&#xff0c;这不仅让我们难以捕捉到每一个细节&#xff0c;更可能让我们错失视频所要传…