随笔 - 18  文章 - 0  评论 - 2  阅读 - 6835

贝叶斯分类器

贝叶斯分类器

贝叶斯分类器是一种基于贝叶斯定理的统计分类方法,通常用于文本分类、垃圾邮件过滤、情感分析等应用。它的原理和步骤涉及概率、贝叶斯定理和特征提取。下面我将详细解释贝叶斯分类器的原理和步骤。

原理:

贝叶斯分类器基于贝叶斯定理,用于预测给定某个特征条件下的类别概率。贝叶斯定理描述了在已知先验概率的情况下,如何计算后验概率。在分类问题中,我们希望找到最可能的类别,即在给定特征的情况下,类别的后验概率最大。

步骤:

贝叶斯分类器的工作步骤可以分为以下几个阶段:

  1. 数据准备: 首先,需要准备带有标签的训练数据集。数据集包括样本的特征和相应的类别标签。
  2. 特征提取: 特征提取是将文本数据或其他数据转换为机器学习算法可以理解的数字特征的过程。在文本分类中,常见的特征提取方法包括词袋模型(Bag of Words)和TF-IDF(Term Frequency-Inverse Document Frequency)。
  3. 计算先验概率: 先验概率是在没有观察到特征时每个类别的概率。它可以通过训练数据中各类别的样本数量来估计。通常,先验概率可以表示为 P(Ci),其中 Ci 是类别i
  4. 计算条件概率: 条件概率表示在给定某一特征的情况下,样本属于某个类别的概率。条件概率可以通过训练数据中特征在各个类别下的出现频率来估计。通常,条件概率可以表示为 P(xi|Ci),其中 xi 是特征,Ci 是类别 i
  5. 计算后验概率: 利用贝叶斯定理,可以计算在给定特征的情况下,每个类别的后验概率。后验概率可以表示为 P(Ci|X)=(P(X|Ci)P(Ci))/P(X),其中 X 是观察到的特征。
  6. 分类决策: 选择具有最高后验概率的类别作为最终的分类结果。通常,决策规则是选择 argmax(P(Ci|X)),即具有最大后验概率的类别。
  7. 模型评估: 对分类器的性能进行评估,通常使用交叉验证、准确率、召回率、F1分数等指标来评估分类器的性能。
  8. 应用: 在实际应用中,可以使用训练好的贝叶斯分类器来对新样本进行分类。

朴素贝叶斯分类器:

朴素贝叶斯分类器是贝叶斯分类器的一个常见变体。它假设特征之间是相互独立的,这被称为“朴素”的假设。虽然这个假设在现实中不一定成立,但朴素贝叶斯分类器仍然表现出色,并且在文本分类等任务中非常有效。它的计算简单,适用于高维数据和大规模数据集。

源代码

BayesClassifier.py

import numpy as np
from sklearn.model_selection import train_test_split
import warnings

warnings.filterwarnings("ignore")  # 消除警告


class Bayes_Classifier(object):
    """贝叶斯分类器"""

    def __init__(self):
        """定义训练集"""
        self.X_train = None
        self.y_train = None

    def fit(self, X_train, y_train):
        # 给训练集赋值
        """
        X_train is array, shape like [n_samples, n_features]
        y_train is array, shape like [n_samples,]
        """
        self.X_train = X_train
        self.y_train = y_train

    def cal_base_rates(self):
        """
        计算先验概率
        data为训练集
        """
        cal_base_rates = {}
        # 首先查看数据一共有几个决策属性
        labels = self.Get_Decision_attribute()

        # 计算先验概率
        for label in labels:
            # 如 :  '是'在y_train_data中出现的次数 / 在y_train_data的长度
            priori_prob = self.y_train(label) / len(self.y_train)
            # 放入字典中
            cal_base_rates[label] = priori_prob

        return cal_base_rates

    def Get_Decision_attribute(self):
        """获得数据集的决策属性"""
        labels = set(self.y_train)
        return labels

    def Conditional_Probability(self, X_test):
        labels = self.Get_Decision_attribute()
        labels_count = {}
        labels_place = {}
        #  存放后验概率
        cal_base_rates = {}

        for label in labels:
            labels_count[label] = sum(self.y_train == label)
            labels_place[label] = np.argwhere(self.y_train == label)
            cal_base_rates[label] = []  #  初始化

        flag = 0
        # 计算每个属性的条件概率
        for value in X_test:
            # 对连续值的处理
            if type(value) != str:
                for label, places in labels_place.items():
                    int_value = []
                    for place in places:
                        int_value.append(
                            self.X_train[place, flag]
                        )  # 将取值放入,方便等会计算均值,标准差
                    #  计算均值,标准差
                    value_mean = np.mean(int_value)
                    value_std = np.std(int_value)

                    # 高斯模型
                    race = (
                        np.exp(((value - value_mean) ** 2) / (-2 * (value_std**2)))
                    ) / (np.sqrt(2 * np.pi) * value_std)
                    cal_base_rates[label].append(race)

            # 对离散值的处理
            else:
                for label, places in labels_place.items():  #
                    value_count = 0
                    for place in places:
                        if value == self.X_train[place, flag]:
                            value_count += 1
                    # 计算概率
                    race = value_count / len(places)
                    cal_base_rates[label].append(race)

            flag = flag + 1

        return cal_base_rates

    def predict(self, X_test):
        from functools import reduce

        # 得出先验概率和后验概率
        result_behind = self.Conditional_Probability(X_test)
        result_before = self.cal_base_rates()

        # 计算概率
        max_race = 0
        flag = None
        for label, value in result_behind.items():
            race = reduce(lambda x, y: x * y, value) * result_before[label]  # 计算概率

            if max_race < race:
                max_race = race
                flag = label

        return flag  # 返回类别

    def score_model(self, X_test, y_test):
        y_pred = [self.predict(item) for item in X_test]
        return np.mean(y_pred == y_test)

说明:

该代码包含了贝叶斯分类器的主要部分,包括训练和预测。

代码详解:

导入库和设置警告

代码首先导入所需的库,包括numpysklearn中的train_test_split,并使用warnings库来消除警告信息。

import numpy as np
from sklearn.model_selection import train_test_split
import warnings

warnings.filterwarnings("ignore")  # 消除警告

类定义:Bayes_Classifier

这个部分定义了一个名为Bayes_Classifier的Python类,表示朴素贝叶斯分类器。以下是类的主要方法和属性的详细解释。

__init__ 方法
def __init__(self):
    """定义训练集"""
    self.X_train = None
    self.y_train = None

该方法是类的构造函数,用于初始化Bayes_Classifier类的实例。它创建了两个属性:X_trainy_train,用于存储训练集的特征和标签。

fit 方法
def fit(self, X_train, y_train):
    """
    X_train is array, shape like [n_samples, n_features]
    y_train is array, shape like [n_samples,]
    """
    self.X_train = X_train
    self.y_train = y_train

fit 方法用于将训练数据(特征和标签)分别存储在X_trainy_train属性中。这是训练模型的第一步。

cal_base_rates 方法
def cal_base_rates(self):
    """
    计算先验概率
    data为训练集
    """
    cal_base_rates = {}
    # 首先查看数据一共有几个决策属性
    labels = self.Get_Decision_attribute()

    # 计算先验概率
    for label in labels:
        # 如 :  '是'在y_train_data中出现的次数 / 在y_train_data的长度
        priori_prob = self.y_train(label) / len(self.y_train)
        # 放入字典中
        cal_base_rates[label] = priori_prob

    return cal_base_rates

cal_base_rates 方法计算模型的先验概率,即每个类别的概率。这是朴素贝叶斯分类器中的重要步骤,它用于估计每个类别在数据集中出现的概率。

Get_Decision_attribute 方法
def Get_Decision_attribute(self):
    """获得数据集的决策属性"""
    labels = set(self.y_train)
    return labels

Get_Decision_attribute 方法用于获取数据集的决策属性,也就是数据集中所有可能的类别标签。

Conditional_Probability 方法
def Conditional_Probability(self, X_test):
    # ...(代码略,详细解释见下方)
    return cal_base_rates

Conditional_Probability 方法用于计算条件概率。这个方法接受一个测试数据集 X_test 作为输入,然后计算每个属性的条件概率。它包括处理连续值和离散值的逻辑。

predict 方法
def predict(self, X_test):
    # ...(代码略,详细解释见下方)
    return flag  # 返回类别

predict 方法用于根据条件概率来预测输入数据点所属的类别。它计算后验概率并选择概率最大的类别作为预测结果。

score_model 方法
def score_model(self, X_test, y_test):
    y_pred = [self.predict(item) for item in X_test]
    return np.mean(y_pred == y_test)

score_model 方法用于评估模型性能。它接受测试数据集 X_test 和相应的真实标签 y_test,并返回模型的性能得分。在这里,性能得分是模型正确分类的数据点所占的比例。

Conditional_Probability 方法详解

Conditional_Probability 方法是整个朴素贝叶斯分类器的核心。它计算条件概率,分为以下几个步骤:

  1. 获取决策属性标签集合(类别标签)。
  2. 初始化用于存储类别计数、类别位置和后验概率的字典。
  3. 遍历每个属性值,对连续值和离散值采用不同的处理方式。
  4. 对连续值:计算每个类别的均值和标准差,然后使用高斯模型计算概率。
  5. 对离散值:计算每个类别中与属性值相等的样本数,并计算概率。
  6. 返回计算后的后验概率。
predict 方法详解

predict 方法用于预测输入的数据点所属的类别。它的步骤如下:

  1. 计算后验概率,即每个类别的后验概率。
  2. 对每个类别,计算属性条件概率的乘积,然后与先验概率相乘,得到一个概率值。
  3. 选择具有最高概率的类别作为预测结果。

train.py

import pandas as pd
import numpy as np
import pickle
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import (
    accuracy_score,
    f1_score,
    roc_auc_score,
    recall_score,
    precision_score,
)
from sklearn.model_selection import StratifiedKFold
from BayesClassifier import Bayes_Classifier
import jieba

# 读取训练数据
train_data = pd.read_csv("cnews.train.txt", sep="\t", names=["label", "content"])
val_data = pd.read_csv("cnews.val.txt", sep="\t", names=["label", "content"])


# 读取分类目录函数
def read_category(y_data):
    categories = ["体育", "财经", "房产", "家居", "教育", "科技", "时尚", "时政", "游戏", "娱乐"]
    categories = [x for x in categories]
    cat_to_id = dict(zip(categories, range(len(categories))))
    label_id = [cat_to_id[y] for y in y_data]
    return label_id


train_target = train_data["label"]
y_train = read_category(train_target)
val_target = val_data["label"]
y_val = read_category(val_target)


# 中文分词
def chinese_word_cut(mytext):
    return " ".join(jieba.cut(mytext))


train_data["content"] = train_data["content"].apply(chinese_word_cut)
val_data["content"] = val_data["content"].apply(chinese_word_cut)

# TF-IDF 特征提取
# f_all = pd.concat(objs=[train_data["content"], val_data["content"]], axis=0)
tfidf_vect = TfidfVectorizer(max_df=0.9, min_df=3, token_pattern=r"(?u)\b\w+\b")
# tfidf_vect.fit(f_all)
# X_train = tfidf_vect.transform(train_data["content"])
# X_val = tfidf_vect.transform(val_data["content"])
# 使用训练数据进行TF-IDF拟合
X_train = tfidf_vect.fit_transform(train_data["content"])

# 使用验证数据进行TF-IDF转换
X_val = tfidf_vect.transform(val_data["content"])

with open("tfidf_vectorizer.pkl", "wb") as vectorizer_file:
    pickle.dump(tfidf_vect, vectorizer_file)

# K折交叉验证
n_splits = 5
skf = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=42)

for fold_n, (train_index, val_index) in enumerate(skf.split(X_train, y_train), 1):
    X_trn, X_val = X_train[train_index], X_train[val_index]
    y_trn, y_val = [y_train[i] for i in train_index], [y_train[i] for i in val_index]

    # 创建并训练模型
    clf = MultinomialNB()
    # clf = Bayes_Classifier()
    clf.fit(X_trn, y_trn)

    # 预测验证集
    y_val_pred = clf.predict(X_val)

    # 计算性能指标
    f1_score_value = f1_score(y_val, y_val_pred, average="micro")
    accuracy_score_value = accuracy_score(y_val, y_val_pred)
    roc_auc_score_value = roc_auc_score(
        y_val, clf.predict_proba(X_val), multi_class="ovr"
    )
    recall_score_value = recall_score(y_val, y_val_pred, average="micro")
    precision_score_value = precision_score(y_val, y_val_pred, average="micro")

    # 输出结果
    print(f"Fold {fold_n}:")
    print(f"  F1 Score: {f1_score_value* 100:.2f}%")
    print(f"  Accuracy Score: {accuracy_score_value* 100:.2f}%")
    print(f"  ROC AUC Score: {roc_auc_score_value* 100:.2f}%")
    print(f"  Recall Score: {recall_score_value* 100:.2f}%")
    print(f"  Precision Score: {precision_score_value * 100:.2f}%")


print("Cross-validation has completed.")

# 保存最终训练好的模型
clf.fit(X_train, y_train)
with open("naive_bayes_model.pkl", "wb") as model_file:
    pickle.dump(clf, model_file)

print("The training has completed, and the model has been saved.")

代码详解:

在上述代码中,我们使用朴素贝叶斯分类器(Naive Bayes)来完成文本分类任务。代码中使用的主要库包括pandasnumpysklearnjieba以及自定义的BayesClassifier

本文本分类任务的目标是将一组新闻文本按照其内容进行分类。数据集包括训练数据和验证数据,每个文本都附有一个类别标签,如“体育”、“财经”等。代码的主要步骤如下:

  1. 读取训练和验证数据
  2. 定义类别标签转化函数
  3. 对文本进行中文分词
  4. 使用TF-IDF特征提取
  5. 执行K折交叉验证
  6. 训练朴素贝叶斯分类器
  7. 评估模型性能
  8. 保存最终训练好的模型

下面将逐一详细解释每一步。

1. 读取训练和验证数据

代码使用pandas库来读取训练和验证数据。训练数据和验证数据存储在两个文本文件中,这些文件以制表符分隔,每行包含两列:标签(label)和文本内容(content)。以下是代码片段:


val_data = pd.read_csv("cnews.val.txt", sep="\t", names=["label", "content"])

`pd.read_csv`函数将文本文件加载到`pandas`的`DataFrame`数据结构中,其中`sep="\t"`指定了制表符为分隔符,`names`参数用于指定列名。

##### 2. 定义类别标签转化函数

为了让机器学习模型能够处理类别标签,代码定义了一个函数`read_category`,用于将文本类别标签(如“体育”)转化为数字标签。这是因为大多数机器学习模型需要使用数字来表示类别。

```python
def read_category(y_data):
    categories = ["体育", "财经", "房产", "家居", "教育", "科技", "时尚", "时政", "游戏", "娱乐"]
    categories = [x for x in categories]
    cat_to_id = dict(zip(categories, range(len(categories)))
    label_id = [cat_to_id[y] for y in y_data]
    return label_id

该函数首先定义了一个类别列表categories,然后创建了一个字典cat_to_id,将类别标签映射为数字。最后,函数返回类别标签的数字列表。

3. 中文分词

在文本分类任务中,文本数据需要进行处理和预处理。中文分词是一种重要的文本预处理步骤,用于将中文文本拆分成有意义的词语。代码使用了jieba库来进行中文分词。

def chinese_word_cut(mytext):
    return " ".join(jieba.cut(mytext))

chinese_word_cut函数接受一段文本作为输入,并使用jieba.cut函数对文本进行分词,然后将分词结果以空格分隔并返回。

分词后,代码将分词结果应用于训练数据和验证数据的文本内容,以便将它们转化为分词后的形式。

train_data["content"] = train_data["content"].apply(chinese_word_cut)
val_data["content"] = val_data["content"].apply(chinese_word_cut)
4. TF-IDF特征提取

接下来,代码进行了TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频率)特征提取。TF-IDF是一种常用的文本特征提取方法,它用于将文本数据转换为数值特征向量。TF-IDF考虑了词语在文档中的重要性,是一种用于信息检索和文本分类的强大工具。

# 使用训练数据进行TF-IDF拟合
X_train = tfidf_vect.fit_transform(train_data["content"])

# 使用验证数据进行TF-IDF转换
X_val = tfidf_vect.transform(val_data["content"])

现在,X_train包含了训练数据的TF-IDF特征向量,而X_val包含了验证数据的TF-IDF特征向量。

5. 执行K折交叉验证

为了评估朴素贝叶斯模型的性能,代码执行了K折交叉验证。这是一种常用的模型评估方法,其中数据被分为K份,模型被多次训练和

测试以获得可靠的性能指标。

n_splits = 5
skf = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=42)

在这里,n_splits指定了将数据分为5份,StratifiedKFold用于执行分层K折交叉验证,确保每个折叠中的类别分布与整个数据集中的类别分布相似。

在每个折叠中,代码按照如下步骤执行交叉验证:

  • 划分训练集和验证集
  • 创建并训练朴素贝叶斯分类器
  • 预测验证集
  • 计算性能指标(F1分数、准确率、ROC AUC分数、召回率和精度)
  • 输出性能结果

这个过程会循环5次,每次使用不同的验证集。

6. 训练朴素贝叶斯分类器

在每个交叉验证折叠中,代码创建并训练了一个MultinomialNB朴素贝叶斯分类器。朴素贝叶斯是一种常用的文本分类算法,适用于文本数据的处理。

clf = MultinomialNB()
clf.fit(X_trn, y_trn)

clf.fit方法用训练数据来拟合模型,将TF-IDF特征向量与相应的类别标签关联起来。

7. 评估模型性能

在每个交叉验证折叠中,模型在验证集上进行预测,并计算多个性能指标,包括F1分数、准确率、ROC AUC分数、召回率和精度。

y_val_pred = clf.predict(X_val)
f1_score_value = f1_score(y_val, y_val_pred, average="micro")
accuracy_score_value = accuracy_score(y_val, y_val_pred)
roc_auc_score_value = roc_auc_score(y_val, clf.predict_proba(X_val), multi_class="ovr")
recall_score_value = recall_score(y_val, y_val_pred, average="micro")
precision_score_value = precision_score(y_val, y_val_pred, average="micro")

这些指标用于评估模型的分类性能,以便了解模型在不同折叠中的表现。

8. 保存最终训练好的模型

最后,代码使用所有的训练数据来训练一个最终的朴素贝叶斯模型,并将模型保存到文件"naive_bayes_model.pkl"中。

clf.fit(X_train, y_train)
with open("naive_bayes_model.pkl", "wb") as model_file:
    pickle.dump(clf, model_file)

这个模型可以用于将来对新文本进行分类。

test.py

import pandas as pd
import jieba
import pickle
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score

# 读取测试数据
test_data = pd.read_csv("cnews.test.txt", sep="\t", names=["label", "content"])


# 读取分类目录函数
def read_category(y_data):
    categories = ["体育", "财经", "房产", "家居", "教育", "科技", "时尚", "时政", "游戏", "娱乐"]
    categories = [x for x in categories]
    cat_to_id = dict(zip(categories, range(len(categories))))
    label_id = [cat_to_id[y] for y in y_data]
    return label_id


test_target = test_data["label"]
y_test = read_category(test_target)


# 中文分词
def chinese_word_cut(mytext):
    return " ".join(jieba.cut(mytext))


test_data["content"] = test_data["content"].apply(chinese_word_cut)

# 加载训练好的TF-IDF向量化器
with open("tfidf_vectorizer.pkl", "rb") as vectorizer_file:
    tfidf_vect = pickle.load(vectorizer_file)

# TF-IDF特征提取
X_test = tfidf_vect.transform(test_data["content"])

# 加载训练好的模型
with open("naive_bayes_model.pkl", "rb") as model_file:
    clf = pickle.load(model_file)

# # 预测
# y_pred = clf.predict(X_test)

# # 评估性能
# accuracy = accuracy_score(y_test, y_pred)
# print("Test Accuracy: {:.2f}%".format(accuracy * 100))

from sklearn.metrics import (
    accuracy_score,
    f1_score,
    roc_auc_score,
    recall_score,
    precision_score,
)

# 预测、性能评估
y_test_pred = clf.predict(X_test)
f1_score_testue = f1_score(y_test, y_test_pred, average="micro")
accuracy_score_testue = accuracy_score(y_test, y_test_pred)
roc_auc_score_testue = roc_auc_score(
    y_test, clf.predict_proba(X_test), multi_class="ovr"
)
recall_score_testue = recall_score(y_test, y_test_pred, average="micro")
precision_score_testue = precision_score(y_test, y_test_pred, average="micro")

# 输出结果
print(f"  F1 Score: {f1_score_testue* 100:.2f}%")
print(f"  Accuracy Score: {accuracy_score_testue* 100:.2f}%")
print(f"  ROC AUC Score: {roc_auc_score_testue* 100:.2f}%")
print(f"  Recall Score: {recall_score_testue* 100:.2f}%")
print(f"  Precision Score: {precision_score_testue * 100:.2f}%")

代码详解:

该部分代码用于使用已经训练好的朴素贝叶斯分类器模型对测试数据进行分类,并评估模型的性能。测试数据包括将新的文本数据转换为特征向量,然后使用模型进行预测,最后计算性能指标。

加载训练好的模型

代码从文件中加载保存的已经训练好的朴素贝叶斯分类器模型。

with open("naive_bayes_model.pkl", "rb") as model_file:
    clf = pickle.load(model_file)

现在,clf包含了加载的模型。

预测和性能评估

现在,模型已经准备好进行预测。代码使用已经训练好的朴素贝叶斯分类器模型 clf 对测试数据进行预测,并计算性能评估指标。

y_test_pred = clf.predict(X_test)

y_test_pred 包含了模型对测试数据的类别预测结果。代码以百分比形式打印这些指标的值。

训练与测试结果

对模型进行训练并进行K折交叉验证,验证集的测试结果如下所示,准确率还是比较可观:

image

将训练好的模型用测试集进行测试:

image

准确度相对还是比较可观。

posted on   CyberFisher  阅读(186)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示