NLP09-朴素贝叶斯问句分类(3/3)

news/2025/2/27 5:17:31

首先有个问句分类类

python">class QuestionClassify:

以下均为该类中的属性

python">    def __init__(self):
        self.train_x = None
        self.train_y = None
        self.tfidf_vec = None
        self.train_vec = None
        self.model = None
        self.question_category_dict = None

__init__ 是 Python 中的一个特殊方法(也叫构造函数),它在创建类的实例时自动调用,用于初始化对象的属性。

  • self.train_x:实例属性,用于存储训练数据的文本(即问题文本)
  • self.train_y:实例属性,用于存储训练数据的标签(即每个问题的类别标签)。
  • self.tfidf_vec:实例属性,用于存储 TfidfVectorizer 对象。TfidfVectorizer 是一个用于文本向量化的工具。
  • self.train_vec:实例属性,用于存储文本经过 TfidfVectorizer 转换后的向量表示。
  • self.model:用于存储分类模型。
  • self.question_category_dict:用于存储问题类别与标签的映射字典。

以下均为该类中的方法。 

一、文本向量化

为什么要进行文本向量化?

因为计算机只能处理数字,不能直接理解文字。向量化后的结果是一个数值向量,通常是一个数组或列表,里面的每个数值代表文本的某种特征。具体是什么数值项,取决于使用的向量化方法。

1. 词袋模型(Bag of Words, BoW)

  • 结果:向量中的每个数值表示某个词在文本中出现的次数

2. TF-IDF(词频-逆文档频率)

  • 结果:向量中的每个数值表示某个词的重要性(考虑词频和全局文档频率)。详见 NLP05-jieba分词

代码呈现

python">    # 文本向量化
    def to_vect(self):
        if self.tfidf_vec is None:
            # 加载训练数据
            self.train_x, self.train_y = data_loader.load_train_data()
            # 初始化一个Tfidf
            self.tfidf_vec = TfidfVectorizer()
            # 确保 self.train_x 是字符串列表
            if isinstance(self.train_x[0], list):
                self.train_x = [" ".join(doc) for doc in self.train_x]
            self.train_vec = self.tfidf_vec.fit_transform(self.train_x).toarray()
            # print(self.train_vec)

难点代码解析:

python"> self.train_vec = self.tfidf_vec.fit_transform(self.train_x).toarray()
  • fit_transform 方法首先学习文本数据的词汇表和 IDF(逆文档频率),然后将文本数据转换为 TF-IDF 特征矩阵
  • toarray() 方法将稀疏矩阵转换为密集矩阵(二维数组),方便后续处理。

重点讲解 toarray() 方法是如何将稀疏矩阵转换为密集矩阵的?

首先,我们要了解稀疏矩阵的存储方式:

假设有一个稀疏矩阵sparse_matrix,如下所示:

python">from scipy.sparse import csr_matrix

# 创建一个CSR矩阵
row_indices = [0, 1, 2]
col_indices = [0, 2, 1]
data = [1, 3, 2]
sparse_matrix = csr_matrix((data, (row_indices, col_indices)), shape=(3, 3))

# 转换为NumPy数组
dense_matrix = sparse_matrix.toarray()

print(dense_matrix)

输出结果为:

python">[[1 0 0]
 [0 0 3]
 [0 2 0]]

通过这个栗子我们可以看出,稀疏矩阵是为了节省内存空间,只存储非零元素以及它们的位置,而对于零元素则不存储。这样,对于大多数元素是零的矩阵,稀疏矩阵比密集矩阵更节省内存。

其次,转换为密集矩阵

python"># 将稀疏矩阵转换为密集矩阵
dense_matrix = sparse_matrix.toarray()

print(dense_matrix)

输出结果为:

python">[[1 0 0]
 [0 0 3]
 [0 2 0]]

虽然矩阵的维度没有改变,都是从3x3到3x3矩阵的转变,但在内存中的存储方式发生了变化,导致内存占用从稀疏变为密集。

我自己的迷思又想明白的问题:

这个例子中,矩阵从3x3到3x3具有极大的迷惑性,让我刚开始难以理解为什么第一种更稀疏。是因为这个例子比较特殊,正好有三个非零值,所以两个矩阵维度是一样的,但是如果零值多了,远大于非零值,就很容易想明白稀疏矩阵更省内存了!稀疏矩阵的优势主要体现在当零值占大多数时,它能够显著节省内存,因为它只存储非零值及其位置,而忽略零值。

这样做有什么好处?

参考 【机器学习】.toarray()表示什么意思

 二、模型训练

模块代码

python">    # 模型训练
    def train_model(self):
        self.to_vect()
        nb_model = MultinomialNB(alpha=0.01)
        nb_model.fit(self.train_vec, self.train_y)
        self.model = nb_model

  先调用类中的 to_vect() 方法进行文本向量化。

 难点代码解析

python">nb_model = MultinomialNB(alpha=0.01)
  • MultinomialNB:朴素贝叶斯分类器,适用于多项式分布的特征,广泛用于文本分类问题。
  • alpha=0.01:这是一个平滑参数,通常用于防止出现零概率。alpha 的值越小,平滑的效果越小,越接近于原始数据分布。alpha=0.01 表示轻度平滑。

详细介绍 alpha 参数的底层原理:

(1) 朴素贝叶斯的概率计算

(2)当 alpha=0 时

        如果某个特征 xi​ 在训练数据中没有出现过(即出现次数为 0),那么 P(xi∣y)=0。

        由于朴素贝叶斯模型是概率是连乘的,只要有一个特征的概率为 0,整个概率就会变成 0。这会导致模型无法处理新数据中出现的未知特征,从而过拟合训练数据。

(3)当 alpha>0

        平滑 的作用是给所有特征一个很小的概率,确保即使某个特征在某个类别中没有出现,它也不会被赋值为零。这样可以避免模型过于依赖已知特征,增加模型的泛化能力。

举个栗子:

假设我们有一个文本分类任务,类别为“体育”和“科技”,词汇表为 ["篮球", "足球", "人工智能"]

训练数据:

  • 体育类文本:["篮球", "足球"]

  • 科技类文本:["人工智能"]

测试数据

  • 新文本:["篮球", "人工智能", "网球"](“网球”是训练数据中未出现过的词)

连乘不为 0:模型可以基于平滑后的概率值,综合考虑其他已知特征的信息,对新数据中的未知特征进行合理处理。

python">nb_model.fit(self.train_vec, self.train_y)

fit() 方法作用是训练模型,会根据 train_vec 中的特征和 train_y 中的标签,训练朴素贝叶斯模型,并调整模型的内部参数。

易混点:

fit_transform() 方法

  • 库: sklearn(scikit-learn)中的特征转换方法
  • 工作原理: 它先 fit 即根据输入数据学习一些信息(如计算特征的统计量),然后 transform 即根据学到的信息对数据进行转换(例如,归一化、标准化、向量化等)。
  • 数据预处理时(如文本向量化或标准化)用 fit_transform() 来进行数据转换。比如
python"># 对文本数据进行向量化
tfidf_vec = TfidfVectorizer()
train_vec = tfidf_vec.fit_transform(train_x)  # 学习并转换数据

fit() 方法

  • 库: sklearn(scikit-learn)中的模型训练方法
  • 工作原理: 模型会从给定的训练数据中学习,并根据数据调整其内部参数。
  • 模型训练时,用 fit() 来训练模型。比如
python"># 训练朴素贝叶斯模型
nb_model = MultinomialNB()
nb_model.fit(train_vec, train_y)  # 学习模型参数

三、模型预测

模块代码

python">    # 模型预测
    def predict(self, question):
        # 词性标注做电影相关实体的抽取
        question_cut = nlp_util.movie_pos(question)
        # 原问句列表(刘德华演过哪些电影)
        question_src_list = []
        # 转换后的问句(nr演过哪些电影)
        question_pos_list = []

        for item in question_cut:
            question_src_list.append(item.word)
            if item.flag in ['nr', 'nm', 'nnt']:
                question_pos_list.append(item.flag)
            else:
                question_pos_list.append(item.word)
        question_pos_text = [" ".join(question_pos_list)]
        # print(question_pos_text)
        # 文本向量化
        question_vect = self.tfidf_vec.transform(question_pos_text).toarray()

        # 输入模型进行预测,得到结果
        predict = self.model.predict(question_vect)[0]
        return predict

 难点代码解析

python"> # 文本向量化
question_vect = self.tfidf_vec.transform(question_pos_text).toarray()

transform() 方法

  •  库:sklearn(scikit-learn)中的特征转换方法。
  • 工作原理:它基于之前通过 fit() 方法学到的信息(如特征的统计量或规则),对输入数据进行转换(例如,归一化、标准化、向量化等)。
  • 数据预处理时,如果已经通过 fit() 方法学习了数据的特征信息,可以使用 transform() 方法对新的数据进行转换。

四、输出结果

模块代码

python">    def init_question_category_dict(self):
        # 读取问题(类别-描述)映射文件
        question_category_path = os.path.join(constant.DATA_DIR, "question_classification.txt")
        with open(question_category_path, "r", encoding="utf-8") as file:
            question_category_list = file.readlines()
        self.question_category_dict = {}
        for category_item in question_category_list:
            category_id, category_desc = category_item.strip().split(":")
            self.question_category_dict[int(category_id)] = category_desc

    def get_question_desc(self, category):
        if self.question_category_dict is None:
            self.init_question_category_dict()
        return self.question_category_dict[category]

代码思路

  • init_question_category_dict 方法

    功能:初始化一个字典,存储类别 ID 和类别描述的映射关系。

    步骤:

        从指定路径读取文件 question_classification.txt。

        解析文件的每一行,提取类别 ID 和类别描述。

        将类别 ID 和类别描述的映射关系存储到字典 self.question_category_dict 中。

  • get_question_desc 方法

    功能:根据类别 ID 获取对应的类别描述。

    步骤:

        检查字典 self.question_category_dict 是否已初始化。

        根据传入的类别 ID (预测结果 result)从字典中查找并返回对应的类别描述。

五、完整代码

python">import os.path

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from common import constant

from ch import data_loader, nlp_util


class QuestionClassify:
    def __init__(self):
        self.train_x = None
        self.train_y = None
        self.tfidf_vec = None
        self.train_vec = None
        self.model = None
        self.question_category_dict = None

    # 文本向量化
    def to_vect(self):
        if self.tfidf_vec is None:
            # 加载训练数据
            self.train_x, self.train_y = data_loader.load_train_data()
            # 初始化一个Tfidf
            self.tfidf_vec = TfidfVectorizer()
            # 确保 self.train_x 是字符串列表
            if isinstance(self.train_x[0], list):
                self.train_x = [" ".join(doc) for doc in self.train_x]
            self.train_vec = self.tfidf_vec.fit_transform(self.train_x).toarray()
            # print(self.train_vec)
    # 模型训练
    def train_model(self):
        self.to_vect()
        nb_model = MultinomialNB(alpha=0.01)
        nb_model.fit(self.train_vec, self.train_y)
        self.model = nb_model

    # 模型预测
    def predict(self, question):
        # 词性标注做电影相关实体的抽取
        question_cut = nlp_util.movie_pos(question)
        # 原问句列表(刘德华演过哪些电影)
        question_src_list = []
        # 转换后的问句(nr演过哪些电影)
        question_pos_list = []

        for item in question_cut:
            question_src_list.append(item.word)
            if item.flag in ['nr', 'nm', 'nnt']:
                question_pos_list.append(item.flag)
            else:
                question_pos_list.append(item.word)
        question_pos_text = [" ".join(question_pos_list)]
        # print(question_pos_text)
        # 文本向量化
        question_vect = self.tfidf_vec.transform(question_pos_text).toarray()

        # 输入模型进行预测,得到结果
        predict = self.model.predict(question_vect)[0]
        return predict

    def init_question_category_dict(self):
        # 读取问题(类别-描述)映射文件
        question_category_path = os.path.join(constant.DATA_DIR, "question_classification.txt")
        with open(question_category_path, "r", encoding="utf-8") as file:
            question_category_list = file.readlines()
        self.question_category_dict = {}
        for category_item in question_category_list:
            category_id, category_desc = category_item.strip().split(":")
            self.question_category_dict[int(category_id)] = category_desc

    def get_question_desc(self, category):
        if self.question_category_dict is None:
            self.init_question_category_dict()
        return self.question_category_dict[category]

if __name__ == "__main__":
    classify = QuestionClassify()
    classify.train_model()
    result = classify.predict("刘德华和成龙合作演过哪些电影呢?&&")
    print(classify.get_question_desc(result))
    print(result)

    # classify.init_question_category_dict()
    # print(classify.question_category_dict)


http://www.niftyadmin.cn/n/5869481.html

相关文章

C++ ⾼性能内存池

目录 项⽬介绍 小知识点补充 定位new 英语单词: 什么是内存池 1.池化技术 2.内存池 3.内存池主要解决的问题 3.1 效率问题 3.2 碎片化 3.2.1 外碎片 4.了解一下malloc 先设计⼀个定⻓的内存池 New的实现 Delete的实现 性能测试 脱离malloc直接在…

「软件设计模式」命令模式(Command)

揭秘命令模式:用C实现智能家居的"万能遥控器" 一、从餐厅点餐看命令模式精髓 想象你坐在餐厅点餐时,服务员记录你的订单交给后厨,这个看似简单的过程蕴含着软件设计的智慧。命令模式(Command)正是将这种&quo…

超大规模分类(四):Partial FC

人脸识别任务里,通常利用全连接层,来做人脸的分类。会面临三个实际问题: 真实的人脸识别数据噪声严重真实的人脸识别数据存在严重的长尾分布问题,一些类别样本多,多数类别样本少人脸类别越来越多,全连接层…

Nacos + Dubbo3 实现微服务的Rpc调用

文章目录 概念整理基本概念概念助记前提RPC与HTTP类比RPC接口类的一些理解 实例代码主体结构父项目公共接口项目提供者项目项目结构POM文件实现配置文件实现公共接口实现程序入口配置启动项目检查是否可以注入到Nacos 消费者项目项目结构POM文件实现配置文件实现注册RPC服务类实…

wordpress按不同页调用不同的标题3种形式

在WordPress中,可以通过多种方式根据不同的页面调用不同的标题。这通常用于实现SEO优化、自定义页面标题或根据页面类型显示不同的标题内容。 使用wp_title函数 wp_title函数用于在HTML的title标签中输出页面标题。你可以通过修改主题的header.php文件来实现自定义…

1.2 Kaggle大白话:Eedi竞赛Transformer框架解决方案02-GPT_4o生成训练集缺失数据

目录 0. 本栏目竞赛汇总表1. 本文主旨2. AI工程架构3. 数据预处理模块3.1 配置数据路径和处理参数3.2 配置API参数3.3 配置输出路径 4. AI并行处理模块4.1 定义LLM客户端类4.2 定义数据处理函数4.3 定义JSON保存函数4.4 定义数据分片函数4.5 定义分片处理函数4.5 定义文件名排序…

第6章 数据工程(二)

6.3 数据治理和建模 数据治理是开展数据价值化活动的基础,关注对数字要素的管控能力覆盖组织对数据相关活动的统筹、评估、指导和监督等工作,需要重点关注元数据、数据标准化、数据质量数据模型和数据建模等方面的内容。 6.3.1 元数据 元数据是关于数…

量子计算可能改变世界的四种方式

世界各地的组织和政府正将数十亿美元投入到量子研究与开发中,谷歌、微软和英特尔等公司都在竞相实现量子霸权。 这其中的利害关系重大,有这么多重要的参与者,量子计算机的问世可能指日可待。 为做好准备,,我们必须了…