本次主要用朴素贝叶斯分类器实现鸢尾花数据集的分类:
在这里插入图片描述


1、导入必要的库:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score, classification_report

import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
import numpy as np

导入sklearn的相关库,数据的处理与分析库pandas,数值计算库numpy等等。


2、定义朴素贝叶斯分类器:

fit 函数

  • np.unique(y) 获取 y 中所有不同的类别,并将这些类别存储在 self.classes 中,这里的classes就是['Iris-setosa' 'Iris-versicolor' 'Iris-virginica']
  • 通过 X[y == c] 选择属于类别 c 的所有样本,存储在 X_c 中
  • 均值和方差是按特征计算的,即每个特征有一个均值和一个方差,但是prior只有一个。
  • axis=0 也表示沿着行的方向,即对每一列进行操作

predict函数

  • iterrows() 是 pandas DataFrame 的一个方法,它按行迭代 DataFrame,返回每行的索引和行数据。

_predict函数

  • 用np.log(self.parameters[c][“prior”]) 得到先验概率的对数
  • self.parameters[c][“mean”].values可以得到c类的4个特征的均值,如Iris-setosa的均值是[-1.03396583 0.89321545 -1.31141791 -1.25710072],方差类似。
  • 调用_calculate_likelihood函数求似然,4个特征的似然都求出,然后相乘(因为这里满足独立同分布的假设,所以 P ( x 1 x 2 x 3 x 4 ∣ D ) = P ( x 1 ∣ D ) P ( x 2 ∣ D ) P ( x 3 ∣ D ) P ( x 4 ∣ D ) P(x_1x_2x_3x_4|D)=P(x_1|D)P(x_2|D)P(x_3|D)P(x_4|D) P(x1x2x3x4D)=P(x1D)P(x2D)P(x3D)P(x4D)
    当然了,这里也对其取对数。也就是每个似然的对数和。
  • 通过self.classes[np.argmax(posteriors)] 可以选择最大的概率所对应的类别。
class NaiveBayes:
    def fit(self, X, y):
        self.classes = np.unique(y)
        self.parameters = {}
        for c in (self.classes):
            # 计算每个类别的先验概率
            X_c = X[y == c]
            self.parameters[c] = {
                "mean": X_c.mean(axis=0),
                "var": X_c.var(axis=0),
                "prior": X_c.shape[0] / X.shape[0]
            }
    
    def predict(self, X_test):
        y_pred=[]
        for index, row in X_test.iterrows():
            y_pred.append(self._predict(row.values))
        return np.array(y_pred)
    
    def _predict(self, x):
        posteriors = []
        for c in (self.classes):
            prior = np.log(self.parameters[c]["prior"]) # 先验概率

            mean_values = np.array(self.parameters[c]["mean"].values) # 均值
            var_values = np.array(self.parameters[c]["var"].values) # 方差

            posterior = np.sum(np.log(self._calculate_likelihood(mean_values, var_values,x))) # iid,似然相乘
            posterior = prior + posterior
            posteriors.append(posterior)
        return self.classes[np.argmax(posteriors)] # 返回概率最大的类别
    
    def _calculate_likelihood(self, mean, var, x):
        # 使用高斯分布的概率密度函数
        numerator = np.exp(- (x-mean)**2 / (2 * var))
        denominator = np.sqrt(2 * np.pi * var)
        return numerator / denominator # 返回4个特征的似然概率


注意:
1、算后验概率时无需除以分母,因为分母相同。
2、计算概率的对数而不是直接计算相应的概率。
3、特征是连续的,所以使用告高斯分布计算似然,先验可以在训练模型时计算。
4、贝叶斯其实训练时仅仅就是计算一个先验概率,和一般的神经网络训练过程不同。


3、导入数据并进行预处理:

数据可以上kaggle下载:iris数据集下载

# # 导入本地数据集
df = pd.read_csv('./iris.csv')
df = df.drop(columns=['Id']) # 删除Id列

# 检查数据中的缺失值
print(df.isnull().sum())

# 使用均值填充缺失值
imputer = SimpleImputer(strategy='mean')
df_filled = pd.DataFrame(imputer.fit_transform(df.iloc[:, :-1]), columns=df.columns[:-1])

# 将目标列(如果有缺失值也处理了)添加回来
df_filled['Species'] = df['Species'].values


# 数据标准化
scaler = StandardScaler()
df_filled.iloc[:, :-1] = scaler.fit_transform(df_filled.iloc[:, :-1])


print(df_filled.head())
print("\n\n")

X = df_filled.drop('Species', axis=1)  # 删除目标列来获取特征集
y = df_filled['Species']  # 直接通过列名获取目标变量


print(X.shape)
print(y.shape)
print("\n\n")

1、首先检查数据是否有缺失值,如果有,则进行相应的处理:这里是用均值填充缺失值。
2、然后的、是数据的标准化,处理后得到0均值,标准差为1的数据。


4、分割数据集:

# 分割数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
  • test_size是测试集占数据集的比例
  • 定义random_state的目的是为了确保可重复性,即其值固定时,无论运行这个函数多少次,只要输入数据不变,分割出的训练集和测试集都会是相同的

5、创建分类器实例并进行模型训练:

# 创建朴素贝叶斯分类器实例
model = NaiveBayes()

# 训练模型
model.fit(X_train, y_train)

# 打印fit后的参数
# print(np.array(model.parameters["Iris-setosa"]["var"].values))
# print(model.parameters["Iris-setosa"]["prior"])
# print(model.classes)
# for index, row in X_test.iterrows():
#     print(row.values)
# for x in X_test:
#     print(x)

# print(X_test)

实例化朴素贝叶斯分类器,并调用fit函数计算先验概率。


6、测试结果并打印准确率:

# 预测测试集结果
y_pred = model.predict(X_test)

# print(y_pred)
# print(y_test)
# 计算准确率
accuracy = np.mean(y_pred == y_test)
print(f"Accuracy: {accuracy}")

测试结果,输出准确率。


这里只有4个特征,所以在数据处理时并没有考虑降维。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐