朴素贝叶斯分类(鸢尾花数据集)
fit 函数获取 y 中所有不同的类别,并将这些类别存储在 self.classes 中,这里的classes就是通过 X[y == c] 选择属于类别 c 的所有样本,存储在 X_c 中均值和方差是按特征计算的,即每个特征有一个均值和一个方差,但是prior只有一个。axis=0 也表示沿着行的方向,即对每一列进行操作predict函数iterrows() 是 pandas DataFrame
·
本次主要用朴素贝叶斯分类器实现鸢尾花数据集的分类:
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(x1x2x3x4∣D)=P(x1∣D)P(x2∣D)P(x3∣D)P(x4∣D)
当然了,这里也对其取对数。也就是每个似然的对数和。 - 通过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个特征,所以在数据处理时并没有考虑降维。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献10条内容
所有评论(0)