文章目录
前言
多加学习和理解不同机器学习算法,因此写下这篇关于GaussianNB(高斯朴素贝叶斯)算法的详细伪代码以及计算过程。
一、GaussianNB
1.1 GaussianNB是什么?
高斯朴素贝叶斯,特征变量是连续变量,符合高斯分布,比如说花的宽度高度以及寿命的长度。
1.2 GaussianNB伪代码
下面是 GaussianNB(高斯朴素贝叶斯)算法的详细伪代码和计算过程:
输入:训练集
D
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
n
,
y
n
)
}
D = \{(x_1, y_1), (x_2, y_2), ..., (x_n, y_n)\}
D={(x1,y1),(x2,y2),...,(xn,yn)},其中
x
i
=
(
x
i
1
,
x
i
2
,
.
.
.
,
x
i
d
)
x_i = (x_{i1}, x_{i2}, ..., x_{id})
xi=(xi1,xi2,...,xid) 是
d
d
d 维特征向量,
y
i
y_i
yi 是样本的类别,
y
i
∈
{
c
1
,
c
2
,
.
.
.
,
c
k
}
y_i \in \{c_1, c_2, ..., c_k\}
yi∈{c1,c2,...,ck}。
输出:GaussianNB 分类模型。
-
对于每个类别 c j c_j cj:
- 计算先验概率 P ( y = c j ) = ∑ i = 1 n I ( y i = c j ) n P(y = c_j) = \frac{\sum_{i=1}^n I(y_i = c_j)}{n} P(y=cj)=n∑i=1nI(yi=cj),其中 I I I 是指示函数。
- 对于每个特征维度
j
j
j:
- 计算该类别在每个特征维度上的均值 μ j = ∑ i = 1 n x i j I ( y i = c j ) ∑ i = 1 n I ( y i = c j ) \mu_{j} = \frac{\sum_{i=1}^n x_{ij} I(y_i = c_j)}{\sum_{i=1}^n I(y_i = c_j)} μj=∑i=1nI(yi=cj)∑i=1nxijI(yi=cj) 和方差 σ j 2 = ∑ i = 1 n ( x i j − μ j ) 2 I ( y i = c j ) ∑ i = 1 n I ( y i = c j ) \sigma_{j}^2 = \frac{\sum_{i=1}^n (x_{ij} - \mu_{j})^2 I(y_i = c_j)}{\sum_{i=1}^n I(y_i = c_j)} σj2=∑i=1nI(yi=cj)∑i=1n(xij−μj)2I(yi=cj)。
-
返回模型,包括先验概率 P ( y = c j ) P(y = c_j) P(y=cj) 和每个特征维度的高斯分布参数 ( μ j , σ j 2 ) (\mu_{j}, \sigma_{j}^2) (μj,σj2)。
-
对于新样本 x ^ \hat{x} x^ 的分类:
- 对于每个类别
c
j
c_j
cj:
- 计算后验概率 P ( c j ∣ x ^ ) = P ( y = c j ) ∏ i = 1 d 1 2 π σ j i 2 exp ( − ( x ^ i − μ j i ) 2 2 σ j i 2 ) P(c_j | \hat{x}) = P(y = c_j) \prod_{i=1}^d \frac{1}{\sqrt{2\pi\sigma_{ji}^2}} \exp\left(-\frac{(\hat{x}_i - \mu_{ji})^2}{2\sigma_{ji}^2}\right) P(cj∣x^)=P(y=cj)∏i=1d2πσji21exp(−2σji2(x^i−μji)2)。
- 返回具有最大后验概率的类别作为预测结果。
- 对于每个类别
c
j
c_j
cj:
接下来,我们详细解释一下伪代码中各个步骤的计算过程:
-
计算先验概率 P ( y = c j ) P(y = c_j) P(y=cj):
- 统计训练集中属于类别 c j c_j cj 的样本数量并除以总样本数 n n n。
-
计算均值和方差:
- 对于每个特征维度
j
j
j 和每个类别
c
j
c_j
cj:
- 统计属于类别
c
j
c_j
cj 的样本在特征维度
j
j
j 上的取值,并计算均值
μ
j
\mu_{j}
μj 和方差
σ
j
2
\sigma_{j}^2
σj2。
- 计算均值 μ j \mu_{j} μj:将属于类别 c j c_j cj 的样本在特征维度 j j j 上的取值求和,并除以属于类别 c j c_j cj 的样本数。
- 计算方差 σ j 2 \sigma_{j}^2 σj2:将属于类别 c j c_j cj 的样本在特征维度 j j j 上的取值与均值 μ j \mu_{j} μj 的差的平方求和,并除以属于类别 c j c_j cj 的样本数。
- 统计属于类别
c
j
c_j
cj 的样本在特征维度
j
j
j 上的取值,并计算均值
μ
j
\mu_{j}
μj 和方差
σ
j
2
\sigma_{j}^2
σj2。
- 对于每个特征维度
j
j
j 和每个类别
c
j
c_j
cj:
-
返回模型:
- 将先验概率 P ( y = c j ) P(y = c_j) P(y=cj) 和每个特征维度的高斯分布参数 ( μ j , σ j 2 ) (\mu_{j}, \sigma_{j}^2) (μj,σj2) 组成分类模型。
-
对于新样本 x ^ \hat{x} x^ 的分类:
- 对于每个类别
c
j
c_j
cj:
- 计算后验概率
P
(
c
j
∣
x
^
)
P(c_j | \hat{x})
P(cj∣x^):
- 计算高斯概率密度函数 1 2 π σ j i 2 exp ( − ( x ^ i − μ j i ) 2 2 σ j i 2 ) \frac{1}{\sqrt{2\pi\sigma_{ji}^2}} \exp\left(-\frac{(\hat{x}_i - \mu_{ji})^2}{2\sigma_{ji}^2}\right) 2πσji21exp(−2σji2(x^i−μji)2),其中 x ^ i \hat{x}_i x^i 是新样本在特征维度 i i i 上的取值, μ j i \mu_{ji} μji 是类别 c j c_j cj 在特征维度 i i i 上的均值, σ j i 2 \sigma_{ji}^2 σji2 是类别 c j c_j cj 在特征维度 i i i 上的方差。
- 将每个特征维度上的高斯概率密度函数相乘,再乘以先验概率 P ( y = c j ) P(y = c_j) P(y=cj),得到后验概率 P ( c j ∣ x ^ ) P(c_j | \hat{x}) P(cj∣x^)。
- 计算后验概率
P
(
c
j
∣
x
^
)
P(c_j | \hat{x})
P(cj∣x^):
- 返回具有最大后验概率的类别作为预测结果。
- 对于每个类别
c
j
c_j
cj:
1.3 简化的数据集来说明 GaussianNB 算法的计算过程
假设我们有一个简单的数据集 D,包含两个特征 X1 和 X2,以及对应的类别标签Y。
训练数据集 D:D = { (x1=(0.5, 1.7), y=0), (x2=(1.2, 0.8), y=0), (x3=(2.0, 1.9), y=1), (x4=(3.3, 2.4), y=1) }
计算每个类别的先验概率 P(Y = c):在这个例子中,类别为 0 的样本数量为 2,类别为 1 的样本数量为 2,所以先验概率为 P(Y = 0) = 2/4 = 0.5,P(Y = 1) = 2/4 = 0.5。
计算每个类别在每个特征上的均值和方差:
对于特征 X1:
类别 0 在特征 X1 上的均值 mu[0][1] = (0.5 + 1.2) / 2 = 0.85
类别 0 在特征 X1 上的方差 sigma[0][1] = ((0.5 - 0.85)^2 + (1.2 - 0.85)^2) / 2 ≈ 0.1025
类别 1 在特征 X1 上的均值 mu[1][1] = (2.0 + 3.3) / 2 = 2.65
类别 1 在特征 X1 上的方差 sigma[1][1] = ((2.0 - 2.65)^2 + (3.3 - 2.65)^2) / 2 ≈ 0.7225
对于特征 X2:
类别 0 在特征 X2 上的均值 mu[0][2] = (1.7 + 0.8) / 2 = 1.25
类别 0 在特征 X2 上的方差 sigma[0][2] = ((1.7 - 1.25)^2 + (0.8 - 1.25)^2) / 2 ≈ 0.2025
类别 1 在特征 X2 上的均值 mu[1][2] = (1.9 + 2.4) / 2 = 2.15
类别 1 在特征 X2 上的方差 sigma[1][2] = ((1.9 - 2.15)^2 + (2.4 - 2.15)^2) / 2 ≈ 0.0425
对于测试样本 x=(2.8, 2.1),使用高斯朴素贝叶斯分类器进行预测:将 x=(2.8, 2.1) 带入高斯朴素贝叶斯分类器,计算其属于类别 0 和类别 1 的概率:
对于类别 0:
prob_0 = P(Y = 0) * P(X1 = 2.8 | Y = 0) * P(X2 = 2.1 | Y = 0)
≈ 0.5 * 0.6244 * 0.3492 ≈ 0.1089
对于类别 1:
prob_1 = P(Y = 1) * P(X1 = 2.8 | Y = 1) * P(X2 = 2.1 | Y = 1)
≈ 0.5 * 0.0074 * 0.1089 ≈ 0.00040125
由于 prob_0 > prob_1,所以预测样本 x=(2.8, 2.1) 属于类别 0。
二、复现并检验
2.1 复现并封装为类
代码如下(示例):
import numpy as np
from scipy.stats import norm
from sklearn.metrics import accuracy_score
class MYGaussianNB:
def fit(self, X, y):
#训练数据为一个二维数组,其中每一行是一个样本的特征向量。标签是一个一维数组
self.classes = np.unique(y) # 类别
self.class_priors = np.zeros(len(self.classes)) # 每个类别的先验概率
self.means = {} # 每个类别都有个array储存每个特征的均值
self.variances = {} # 每个类别都有个array储存每个特征的方差
for i, class_name in enumerate(self.classes):
class_indices = y == class_name # 为True的索引表示为是该类的样本所在的索引
class_X = X[class_indices] # 根据索引获取该类所有样本
self.class_priors[i] = len(class_X) / len(X) # 获取该类的先验概率
self.means[class_name] = np.mean(class_X, axis=0) # 求出该类样本所有特征下的均值
self.variances[class_name] = np.var(class_X, axis=0)# 求出该类样本所有特征下的方差
def predict(self, X):
y_pred = [] # 创建一个空列表,用于存储预测结果
for x in X: # 对输入的每个样本进行遍历
class_scores = [] # 创建一个空列表,用于存储每个类别的得分
for i, class_name in enumerate(self.classes): # 遍历每个类别和其索引
prior = self.class_priors[i] # 获取当前类别的先验概率
mean = self.means[class_name] # 获取当前类别的均值
variance = self.variances[class_name] # 获取当前类别的方差
likelihood = norm.pdf(x, loc=mean, scale=np.sqrt(variance))
# 计算当前样本在当前类别下的似然概率
score = prior * np.prod(likelihood) # 计算当前样本在当前类别下的得分(先验概率乘以似然概率)
class_scores.append(score) # 将当前类别的得分添加到列表中
y_pred.append(self.classes[np.argmax(class_scores)]) # 将具有最高得分的类别作为预测结果添加到列表中
return y_pred # 返回预测结果列表
2.2 读入数据用作检验
代码如下(示例):
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 加载燕尾花数据集
iris = load_iris()
# 获取特征数据和标签数据
X = iris.data
y = iris.target
# 将数据集切分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=3220822)
# 打印切分后的数据集大小
print("训练集大小:", x_train.shape[0])
print("测试集大小:", x_test.shape[0])
2.3 sklearn自带GaussianNB
from sklearn.naive_bayes import GaussianNB
# 创建高斯朴素贝叶斯模型对象
model = GaussianNB()
# 模型训练
model.fit(x_train, y_train)
# 预测
y_pred = model.predict(x_test)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)
2.4 调用复现GaussianNB
# 创建 GaussianNB 分类器并训练
classifier = MYGaussianNB()
classifier.fit(x_train, y_train)
# 进行预测
y_pred = classifier.predict(x_test)
accuracy = accuracy_score(y_test, y_pred)
accuracy
总结
在这里给出了sklearn库的GaussianNB类与编写的MYGaussianNB类,使用了相同数据集进行验证。同时在前面给出了该算法的伪代码和实际小例运算,方便读者们更好的理解。