机器学习 8 ——朴素贝叶斯
特征条件独立假设
朴素是指每个特征独立地影响结果,整个假设在实际应用中不成立,主要是思想
输入输出的来拟合概率分布,贝叶斯定理,后验概率最大
文章目录
前言
贝叶斯定理
该定理描述了在已知条件概率的情况下,如何计算两个事件联合发生的概率。
对于分类问题,我们假设每个数据点X属于类别Ck的概率,可以通过下面的贝叶斯公式来计算:
先验概率和后验概率
一、先验概率
先验概率是指在考虑任何观测数据之前,对某个事件发生的概率的主观估计或基于以往 经验和知识——历史数据 的概率。
- 通常是在事件发生之前,对事件可能性的预测或估计。在贝叶斯统计推断中,先验概率分布是在考虑任何相关证据之前,对某一数量或命题的置信程度的概率分布。
- 主要基于历史数据、专家经验或主观判断
- 计算后验概率的起点和基础。
例如,在抛硬币的实验中,如果我们在没有进行任何抛硬币的操作之前,根据以往对硬币的认知,认为正面朝上和反面朝上的概率各为 50%,这个 50% 就是先验概率。
二、后验概率
后验概率是得到“结果”的信息后,对原先概率的重新修正。它是基于先验概率和观测数据通过贝叶斯定理计算得到的。
- 在贝叶斯公式中,后验概率是似然函数与先验概率的乘积,再除以一个标准化常量(即全概率)。
- 基于先验概率和新观察数据的结合
例如,假设我们进行了一系列抛硬币的实验,观察到在多次抛硬币中正面朝上的次数较多,那么根据这些观测数据,我们可以重新计算正面朝上的概率,这个经过观测数据修正后的概率就是后验概率。
例子
任务:将电子邮件分为“垃圾邮件”和“非垃圾邮件”两类。
计算先验概率:
在没有考虑邮件内容之前,我们需要知道邮件是垃圾邮件或非垃圾邮件的先验概率。这通常基于训练数据集中各类别的样本比例。
假设训练数据集中有1000封邮件,其中500封是垃圾邮件,500封是非垃圾邮件。那么,一封邮件是垃圾邮件的先验概率 P(y=垃圾邮件) 就是0.5,非垃圾邮件的先验概率 P(y=非垃圾邮件) 也是0.5。
计算条件概率(似然概率):
对于每个特征(在这里是邮件中的每个单词),我们需要计算在给定类别下该特征出现的条件概率。
例如,假设单词“促销”在垃圾邮件中出现的频率很高,在非垃圾邮件中很少出现。我们可以计算 P(x=促销∣y=垃圾邮件) 和 P(x=促销∣y=非垃圾邮件)。
应用贝叶斯定理:
对于新的邮件,我们需要计算它属于每个类别的后验概率。
使用贝叶斯公式:P(y∣x)=P(x∣y)×P(y)/ P(x)
在这里,P(y∣x) 是后验概率(邮件在给定特征下的类别概率),P(x∣y) 是条件概率(在给定类别下特征出现的概率),P(y) 是先验概率,P(x) 是观测到的特征的边缘概率(通常作为常数,因为对所有类别都相同)。
实际上,只需要比较不同类别的后验概率,所以常常可以省略 P(x) 的计算,因为它对所有类别都是一样的。
分类:
选择具有最高后验概率的类别作为邮件的分类结果。
算法思想
通过给定训练集,学习输入输出的联合概率分布P(x,y)
具体学习方法:
- 学习先验概率分布: P ( Y = c k ) , c k P(Y=c_{k} ),c_{k} P(Y=ck),ck是实例类别
- 学习条件概率分布:
P ( X = x ∣ Y = c k ) = P ( X 1 = x 1 , X 2 = x 2 , . . . , X n = x n ∣ Y = c k ) P(X=x|Y=c_{k} )=P(X^{1}=x^{1} ,X^{2}=x^{2},...,X^{n}=x^{n}|Y=c_{k}) P(X=x∣Y=ck)=P(X1=x1,X2=x2,...,Xn=xn∣Y=ck)
n是实例的维数 - P ( X , Y ) = P ( X = x ∣ Y = c k ) P ( Y = c k ) P(X,Y)=P(X=x|Y=c_{k} )P(Y=c_{k}) P(X,Y)=P(X=x∣Y=ck)P(Y=ck)
但条件概率的估计很难,特别是当x有多个特征,所以有了独立性假设
P
(
X
=
x
∣
Y
=
c
k
)
=
P
(
X
1
=
x
1
∣
Y
=
c
k
)
P
(
X
2
=
x
2
∣
Y
=
c
k
)
⋅
⋅
⋅
P
(
X
n
=
x
n
∣
Y
=
c
k
)
P(X=x|Y=c_{k} )=P(X^{1}=x^{1}|Y=c_{k}) P(X^{2}=x^{2}|Y=c_{k})\cdot \cdot \cdot P(X^{n}=x^{n}|Y=c_{k})
P(X=x∣Y=ck)=P(X1=x1∣Y=ck)P(X2=x2∣Y=ck)⋅⋅⋅P(Xn=xn∣Y=ck)
一、算法
实例的类别是:后验概率最大的类
给定输入x
二、参数估计(先验概率、条件概率)
先验概率(类参数)
就是频率近似概率
例如,有 100 个样本,其中属于类别 c 的有 30 个,那么类别c的先验概率就是 30/100 = 0.3。
条件概率
在已知某个特征的情况下,属于某个类别的概率。概率分布估计其实很多算法都要用到,有很多方法,在之后的算法里慢慢学
离散
例如
对于一个二分类问题,类别为 C1 和 C2,特征x有两个取值 a1 和 a2。
在类别 C1 中,特征 A 取值为 a1 的样本有 20 个,类别 C1 的总样本数量为 50。
那么在类别 C1 下,特征 A 取值为 a1 的条件概率就是 20/50 = 0.4。
连续——高斯分布估计
代码
模拟
import numpy as np
# 定义朴素贝叶斯分类器类
class NaiveBayes:
def __init__(self):
# 初始化先验概率为 None
self.priors = None
# 初始化似然概率为 None
self.likelihoods = None
def fit(self, X, y):
n_samples, n_features = X.shape
# 获取数据集中的不同类别
self.classes = np.unique(y)
n_classes = len(self.classes)
# 计算先验概率
self.priors = np.zeros(n_classes)
for c in self.classes:
# 计算属于每个类别的样本数量占总样本数量的比例,作为先验概率
self.priors[c] = np.sum(y == c) / n_samples
# 计算似然概率
self.likelihoods = np.zeros((n_classes, n_features))
for c in self.classes:
X_c = X[y == c]
for feature_idx in range(n_features):
# 计算每个特征在每个类别下的均值,作为似然概率
self.likelihoods[c, feature_idx] = np.mean(X_c[:, feature_idx])
def predict(self, X):
n_samples = X.shape[0]
# 存储每个样本在不同类别下的后验概率
posteriors = np.zeros((n_samples, len(self.classes)))
for i, sample in enumerate(X):
for c in self.classes:
prior = self.priors[c]
likelihood = np.prod(self.likelihoods[c]**sample * (1 - self.likelihoods[c])**(1 - sample))
# 计算后验概率,即先验概率乘以似然概率
posteriors[i, c] = prior * likelihood
# 返回后验概率最大的类别作为预测结果
return np.argmax(posteriors, axis=1)
def accuracy(self, X, y):
y_pred = self.predict(X)
# 计算预测正确的样本数量占总样本数量的比例,作为准确率
return np.sum(y_pred == y) / len(y)
# 示例数据集
X = np.array([[1, 0], [0, 1], [1, 1], [0, 0]])
y = np.array([0, 1, 0, 1])
# 创建朴素贝叶斯分类器对象并训练
nb = NaiveBayes()
nb.fit(X, y)
# 输入实例进行预测
instance = np.array([1, 1])
predicted_class = nb.predict(np.array([instance]))
print(f"输入实例 {instance} 被预测为类别 {predicted_class[0]}")
# 计算准确率
accuracy = nb.accuracy(X, y)
print(f"估计的准确率为 {accuracy}")
直接调用_准确率非常不准确
CountVectorizer:将文本数据转换为词频矩阵,生成模型可以学习的特征。
MultinomialNB:多项式朴素贝叶斯模型,适用于离散特征的分类任务,如文本分类。
train_test_split:将数据集分成训练集和测试集,70%的数据用于训练,30%的数据用于测试。
# 导入所需库
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
# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target
# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建朴素贝叶斯分类器
gnb = GaussianNB()
# 训练模型
gnb.fit(X_train, y_train)
# 预测测试集结果
y_pred = gnb.predict(X_test)
# 评估准确率
accuracy = accuracy_score(y_test, y_pred)
print(f'Estimated accuracy: {accuracy:.2f}')
# 预测新实例的类别
def predict_new_instance(instance):
prediction = gnb.predict([instance])
return prediction, iris.target_names[prediction[0]]
# 新实例
new_instance = [4.5, 3.0, 1.5, 0.3]
# 预测并输出类别
predicted_category, category_name = predict_new_instance(new_instance)
print(f'The predicted category of the new instance is: {category_name}')