欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > NLP09-朴素贝叶斯问句分类(3/3)

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

2025/6/1 10:24:05 来源:https://blog.csdn.net/m0_74803856/article/details/145858571  浏览:    关键词:NLP09-朴素贝叶斯问句分类(3/3)

首先有个问句分类类

class QuestionClassify:

以下均为该类中的属性

    def __init__(self):self.train_x = Noneself.train_y = Noneself.tfidf_vec = Noneself.train_vec = Noneself.model = Noneself.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分词

代码呈现

    # 文本向量化def to_vect(self):if self.tfidf_vec is None:# 加载训练数据self.train_x, self.train_y = data_loader.load_train_data()# 初始化一个Tfidfself.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)

难点代码解析:

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

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

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

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

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)

输出结果为:

[[1 0 0][0 0 3][0 2 0]]

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

其次,转换为密集矩阵

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

输出结果为:

[[1 0 0][0 0 3][0 2 0]]

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

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

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

这样做有什么好处?

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

 二、模型训练

模块代码

    # 模型训练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() 方法进行文本向量化。

 难点代码解析

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:模型可以基于平滑后的概率值,综合考虑其他已知特征的信息,对新数据中的未知特征进行合理处理。

nb_model.fit(self.train_vec, self.train_y)

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

易混点:

fit_transform() 方法

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

fit() 方法

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

三、模型预测

模块代码

    # 模型预测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

 难点代码解析

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

transform() 方法

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

四、输出结果

模块代码

    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_descdef 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)从字典中查找并返回对应的类别描述。

五、完整代码

import os.pathfrom sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from common import constantfrom ch import data_loader, nlp_utilclass QuestionClassify:def __init__(self):self.train_x = Noneself.train_y = Noneself.tfidf_vec = Noneself.train_vec = Noneself.model = Noneself.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()# 初始化一个Tfidfself.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 predictdef 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_descdef 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)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词