You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

训练测试划分与朴素贝叶斯分类器报错问题求助

问题解析与修正方案

错误原因

这两个警告的核心是你的分类器训练、测试数据完全是单一类别:

  • 用X_train1和y_train1训练伯努利贝叶斯时,y_train1全是easy_ham标签,没有任何spam样本。训练后的模型只会预测easy_ham,根本不会输出spam类别。
  • 计算针对spam的精确率时,因为没有任何预测结果是spam,导致精确率无法计算,被强制设为0.0。
  • 同时y_test1里也全是easy_ham,没有真实的spam样本,召回率同样无法计算,也被设为0.0。

代码核心问题

  1. 数据集拆分逻辑错误:你把三类数据单独拆分训练测试集,而不是合并成完整的二分类数据集(将easy_ham、hard_ham归为非垃圾邮件,spam归为垃圾邮件)。单独用单一类别数据训练,模型学不到区分垃圾邮件的特征。
  2. CountVectorizer使用错误:preprocessing函数里重复创建CountVectorizer()却未使用,且全局vectorizer被多次调用fit_transform,会导致词汇表被覆盖,训练/测试集特征不一致。
  3. 评估逻辑错误:用单一类别数据集计算针对另一类的二分类指标(精确率、召回率)完全没有意义,因为数据里根本没有对应类别样本。

修正后的代码

import tarfile
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB, BernoulliNB
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix


def read_data(file):
    dataset = list()
    with tarfile.open(file) as tar:
        for item in tar:
            if item.isfile():
                with tar.extractfile(item) as f:
                    content = f.read()
                    decoded_content = None
                    for charset in ['utf-8', 'iso-8859-1', 'ascii']:
                        try:
                            decoded_content = content.decode(charset)
                            break
                        except:
                            continue
                    if decoded_content is not None:
                        dataset.append(decoded_content)
    return dataset


# 读取所有数据,统一标签:非垃圾邮件(easy_ham/hard_ham)为0,垃圾邮件(spam)为1
easy_ham = read_data('20021010_easy_ham.tar.bz2')
hard_ham = read_data('20021010_hard_ham.tar.bz2')
spam = read_data('20021010_spam.tar.bz2')

# 合并成完整二分类数据集
X = easy_ham + hard_ham + spam
y = [0]*(len(easy_ham)+len(hard_ham)) + [1]*len(spam)

# 先拆分训练测试集,再做向量化(避免数据泄露)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# 向量化:仅在训练集fit,测试集用相同词汇表transform
vectorizer = CountVectorizer()
X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec = vectorizer.transform(X_test)

# 打印数据集分布
print(f"总样本数: {len(X)},训练集: {len(X_train)},测试集: {len(X_test)}")
print(f"训练集非垃圾邮件数: {y_train.count(0)},垃圾邮件数: {y_train.count(1)}")
print(f"测试集非垃圾邮件数: {y_test.count(0)},垃圾邮件数: {y_test.count(1)}")


def multinomial_classifier(x_train, y_train, x_test, y_test):
    clf = MultinomialNB()
    clf.fit(x_train, y_train)
    predictions = clf.predict(x_test)
    accuracy = accuracy_score(y_test, predictions)
    # 设置zero_division避免极端情况警告
    precision = precision_score(y_test, predictions, pos_label=1, zero_division=1)
    recall = recall_score(y_test, predictions, pos_label=1, zero_division=1)
    confusion_mat = confusion_matrix(y_test, predictions, labels=[0, 1])
    return predictions, accuracy, precision, recall, confusion_mat


def bernoulli_classifier(x_train, y_train, x_test, y_test):
    clf = BernoulliNB()
    clf.fit(x_train, y_train)
    predictions = clf.predict(x_test)
    accuracy = accuracy_score(y_test, predictions)
    precision = precision_score(y_test, predictions, pos_label=1, zero_division=1)
    recall = recall_score(y_test, predictions, pos_label=1, zero_division=1)
    confusion_mat = confusion_matrix(y_test, predictions, labels=[0, 1])
    return predictions, accuracy, precision, recall, confusion_mat


# 评估伯努利贝叶斯
predictions_b, accuracy_b, precision_b, recall_b, confusion_mat_b = bernoulli_classifier(X_train_vec, y_train, X_test_vec, y_test)
print("\n伯努利贝叶斯分类器结果:")
print(f"准确率: {accuracy_b:.4f}")
print(f"垃圾邮件精确率: {precision_b:.4f}")
print(f"垃圾邮件召回率: {recall_b:.4f}")
print("混淆矩阵:")
print(confusion_mat_b)

# 评估多项式贝叶斯
predictions_m, accuracy_m, precision_m, recall_m, confusion_mat_m = multinomial_classifier(X_train_vec, y_train, X_test_vec, y_test)
print("\n多项式贝叶斯分类器结果:")
print(f"准确率: {accuracy_m:.4f}")
print(f"垃圾邮件精确率: {precision_m:.4f}")
print(f"垃圾邮件召回率: {recall_m:.4f}")
print("混淆矩阵:")
print(confusion_mat_m)

关键修正说明

  1. 数据集合并:将easy_ham、hard_ham合并为非垃圾邮件,spam作为垃圾邮件,构建标准二分类数据集。
  2. 正确数据拆分与向量化:先拆分原始文本,再用训练集构建词汇表,测试集复用该词汇表,避免数据泄露。
  3. 处理极端情况:添加zero_division=1参数,解决无预测/无真实样本时的指标计算警告。
  4. 统一特征空间:全局仅初始化一次CountVectorizer,保证训练、测试集特征一致。

内容的提问来源于stack exchange,提问作者yehor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:08:13