[(一)导入 SVM 相关库](#(一)导入 SVM 相关库)
[(二) 修改模型初始化](#(二) 修改模型初始化)
[(三) 比较](#(三) 比较)
支持向量机(SVM)
代码修改基于NLP09-朴素贝叶斯问句分类(3/3)
(一)导入 SVM 相关库
python
from sklearn.svm import SVC # 导入 SVM
(二) 修改模型初始化
python
# 模型训练
def train_model(self):
self.to_vect()
# 使用 SVM 替换朴素贝叶斯
svm_model = SVC(kernel='linear', C=1.0) # 线性核函数,C 是正则化参数
svm_model.fit(self.train_vec, self.train_y)
self.model = svm_model
详细解释SVM
参见**机器学习------支持向量机(SVM)**
python# 使用 SVM 替换朴素贝叶斯 svm_model = SVC(kernel='linear', C=1.0) # 线性核函数,C 是正则化参数
(三) 比较
性能评估指标主要是:准确性、精确率、召回率、F1-Score
朴素贝叶斯分类器
为了进行性能评估,我们需要使用 train_test_split 来分割数据集,并使用 sklearn.metrics 来计算准确性、精确率、召回率和 F1-Score。下面是修改后的完整代码,包含了数据集划分和各项评估指标的计算:
python
import os.path
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
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()
# 模型训练
def train_model(self):
self.to_vect()
# 使用 train_test_split 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(self.train_vec, self.train_y, test_size=0.2, random_state=42)
# 使用朴素贝叶斯模型
nb_model = MultinomialNB(alpha=0.01)
nb_model.fit(X_train, y_train) # 训练模型
self.model = nb_model
# 预测并计算评估指标
y_pred = self.model.predict(X_test)
# 计算并打印评估指标
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average='weighted')
recall = recall_score(y_test, y_pred, average='weighted')
f1 = f1_score(y_test, y_pred, average='weighted')
print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1-Score: {f1:.4f}")
# 模型预测
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)]
# 文本向量化
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)
修改代码解析:
python# 使用 train_test_split 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(self.train_vec, self.train_y, test_size=0.2, random_state=42)
详见 NLP06-Scikit-Learn 机器学习库(鸢尾花为例)的数据集拆分部分。
python# 预测并计算评估指标 y_pred = self.model.predict(X_test) # 计算并打印评估指标 accuracy = accuracy_score(y_test, y_pred) precision = precision_score(y_test, y_pred, average='weighted') recall = recall_score(y_test, y_pred, average='weighted') f1 = f1_score(y_test, y_pred, average='weighted')
这几个指标是常用的分类模型评估指标。
(1) 准确率(Accuracy)
(2) 精确率(Precision)
(3) 召回率(Recall)
(4) F1-Score
输出结果:

SVM分类器
python
import os.path
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC # 导入 SVM
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
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()
# 模型训练
def train_model(self):
self.to_vect()
# 使用 train_test_split 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(self.train_vec, self.train_y, test_size=0.2, random_state=42)
# 使用 SVM(支持向量机)替换朴素贝叶斯
svm_model = SVC(kernel='linear', C=1.0) # 线性核函数,C 是正则化参数
svm_model.fit(X_train, y_train) # 训练模型
self.model = svm_model
# 预测并计算评估指标
y_pred = self.model.predict(X_test)
# 计算并打印评估指标
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred, average='weighted', zero_division=0)
recall = recall_score(y_test, y_pred, average='weighted', zero_division=0)
f1 = f1_score(y_test, y_pred, average='weighted')
print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1-Score: {f1:.4f}")
# 模型预测
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)]
# 文本向量化
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)
输出结果:
分析:
朴素贝叶斯表现更好,可能原因如下:
- 数据集较小:如果数据集较小,朴素贝叶斯可能会比 SVM 表现更好,因为 SVM 需要更多的数据来找到最优超平面。
- 特征独立性假设成立:在文本分类任务中,词语之间的独立性假设可能并不会显著影响朴素贝叶斯的性能。
- 参数调优不当:如果 SVM 的参数(如 C、kernel、gamma)没有调优好,性能可能会较差。
- 类别分布均衡:如果数据集的类别分布较为均衡,朴素贝叶斯的性能可能会更好。