Contents

概率图模型

http://192.168.0.103:7788/images/2023/08/24/image-20230824235302663.png

贝叶斯分类器

概述

贝叶斯分类器是一类基于贝叶斯定理的分类算法,它假设样本的特征在给定类别下是条件独立的,然后通过计算后验概率来进行分类。贝叶斯分类器包括朴素贝叶斯分类器和贝叶斯网络等。

朴素贝叶斯

贝叶斯分类算法是统计学是一种概率分类方法,朴素贝叶斯分类时贝叶斯分类中最简单的一种。

利用贝叶斯公式根据某特征的先验概率计算出其后验概率,然后选择具有最大后验概率的类作为该特征所属的类。

朴素贝叶斯,称之为“朴素”,是因为整个形式化过程只做了最原始、最简单的假设,具体假设如下:

  • 特征之间相互独立
  • 每个特征同等重要

在sklearn中,朴素贝叶斯种类有三种,分别是GaussianNB、MultinomialNB和BernoulliNB。

高斯朴素贝叶斯(GaussianNB)

GaussianNB是先验为高斯分布(正态分布)的朴素贝叶斯,假设每个标签的数据都服从高斯分布(正态分布)。正态分布的概率密度函数计算公式如下: $$ P(X_i=x_i|Y=C_k)=\frac{1}{\sqrt{2\pi\sigma_k^2}}e^{-\frac{(x_i-\mu_k)^2}{2\sigma_k^2}} $$

其中, $C_k$为 Y 的第 k 类类别。 $\mu_k$和$\sigma_k^2$为第 k 类样本在第 i 个属性上的取值的均值和方差。

# 导入包
from sklearn.naive_bayes import GaussianNB  # 高斯分布,假定特征服从正态分布的
from sklearn.model_selection import train_test_split # 数据集划分
from sklearn.metrics import accuracy_score

# 导入数据集
from sklearn import datasets
iris = datasets.load_iris()

# 拆分数据集
train_x,test_x,train_y,test_y = train_test_split(iris.data,iris.target,random_state=12) 

# 建模
gnb_clf = GaussianNB()
gnb_clf.fit(train_x,train_y)

# 对测试集进行预测
# predict():直接给出预测的类别
# predict_proba():输出的是每个样本属于某种类别的概率
predict_class = gnb_clf.predict(test_x)
predict_class_proba = gnb_clf.predict_proba(test_x)
print("测试集准确率为:",accuracy_score(test_y,predict_class))

多项式朴素贝叶斯 (MultinomialNB)

多项式朴素贝叶斯是先验为多项式分布的朴素贝叶斯。 它假设特征是由一个简单多项式分布生成的。多项分布可以描述各种类型样本出现次数的概率,因此多项式朴素贝叶斯非常适合用于描述出现次数的特征。该模型常用于文本分类,特征表示的是次数,例如某个词语的出现次数。 $$ P(X=x_i|Y=C)=\frac{|D_{c,x_i}|+\lambda}{|D_c|+\lambda N_i} $$ 其中, $P(X=x_i|Y=c) $表示 c 类别下第 i 个属性上取值为$x_i$的条件概率。 $|D_c,x_i|$ 是 c 类别下第 i 个属性上取值为$x_i $的样本数,$|D_c|$是 c 类的样本数。 $N_i $表示第 i 个属性可能的取值数。$\lambda$被称为平滑系数,令$\lambda>0$来防止训练数据中出现过的一些词汇没有出现在测试集中导致的0概率。如果$\lambda=1$,则这个平滑叫做拉普拉斯平滑,$\lambda<1$,叫做利德斯通平滑。

class sklearn.naive_bayes.MultinomialNB (alpha=1.0,fit_prior=True, class_prior=None)
# alpha : 浮点数, 可不填 【默认为1.0】
# 平滑系数λ,如果为0,则表示完全没有平滑选项。需注意,平滑相当于人为给概率加上一些噪音,因此λ设置得越大,精确性会越低(虽然影响不是非常大)

# fit_prior : 布尔值, 可不填【默认为True】
# 是否学习先验概率P(Y=c)。如果为False,则所有的样本类别输出都有相同的类别先验概率。即认为每个标签类出现的概率是1/总类别数

# class_prior:形似数组的结构,结构为(n_classes,),可不填【默认为None】 表示类的先验概率P(Y=c)。如果没有给出具体的先验概率则自动根据数据来进行计算。
from sklearn.naive_bayes import MultinomialNB
import numpy as np
# 建立数据集
X = np.random.randint(5, size=(6, 100))
y = np.array([1, 2, 3, 4, 5, 6])
# 建立一个多项式朴素贝叶斯分类器
mnb = MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
mnb.fit(X, y)
# 由于概率永远是在[0,1]之间,mnb给出的是对数先验概率,因此返回的永远是负值
# 类先验概率=各类的个数/类的总个数
print("类先验概率:", np.exp(mnb.class_log_prior_))

# 返回一个固定标签类别下的每个特征的对数概率log(P(Xi | y))
# print("每个特征的对数概率:",mnb.feature_log_prob_)
# '''重要属性:在fit时每个标签类别下包含的样本数。
# 当fit接口中的sample_weight被设置时,
# 该接口返回的值也会受到加权的影响'''
print("每个标签类别下包含的样本数:",mnb.class_count_)
print("预测的分类:", mnb.predict([X[2]]))  # 输出3

伯努利朴素贝叶斯(BernoulliNB)

BernoulliNB就是先验为伯努利分布的朴素贝叶斯。假设特征的先验概率为二元伯努利分布,在文本分类中 ,就是一个特征有没有在一个文档中出现。 $$ P(X=x_i|Y=C)=P(x_i=1|Y=c)x_i+P(x_i=0|Y=c)x_i\ \Downarrow\ P(X=x_i|Y=C)=\frac{|D_{c,x_i}|+\lambda}{|D_c|+2\lambda} $$

class sklearn.naive_bayes.BernoulliNB (alpha=1.0, binarize=0.0,fit_prior=True, class_prior=None)
# binarize:将数据特征二值化的阈值,大于binarize的值处理为1 ,小于等于binarize的值处理为0;
import numpy as np
from sklearn.naive_bayes import BernoulliNB  # 伯努利朴素贝叶斯
x = np.array([[1, 2, 3, 4], [1, 3, 4, 4], [2, 4, 5, 5]])
y = np.array([1, 1, 2])
bnb = BernoulliNB(alpha=2.0, binarize=3.0, fit_prior=True)
bnb.fit(x, y)
print("预测结果:\n",bnb.predict(np.array([[1, 2, 3, 4]])))  # 输出1s

贝叶斯网络

贝叶斯网络(Bayesian Network),又称为信念网络(Belief Network)或概率网络(Probabilistic Network),是一种用图形模型表示变量之间的依赖关系的方法。它基于贝叶斯定理,用有向无环图(DAG)来表示变量之间的条件依赖关系,并使用概率分布来描述变量之间的联合概率分布。

贝叶斯网络的主要特点包括:

  • 有向无环图(DAG)结构: 贝叶斯网络使用有向边表示变量之间的依赖关系,且不允许存在环,这确保了变量之间的关系是有序的。
  • 条件独立性: 贝叶斯网络假设给定父节点的情况下,每个节点与它的非后代节点是条件独立的。这种条件独立性使得贝叶斯网络能够通过已知信息进行推理和预测。
  • 参数化: 贝叶斯网络使用概率分布来描述变量之间的关系。每个节点的条件概率分布由其父节点的状态确定。
from pgmpy.models import BayesianNetwork
from pgmpy.factors.discrete import TabularCPD
from pgmpy.inference import VariableElimination

# 创建贝叶斯网络模型
bayesian_network = BayesianNetwork([('Weather', 'LawnHumidity'),
                                    ('Weather', 'Sprinkler')])

# 定义节点的条件概率分布
cpd_weather = TabularCPD(variable='Weather', variable_card=2,
                         values=[[0.7], [0.3]])
cpd_lawn_humidity = TabularCPD(variable='LawnHumidity', variable_card=2,
                               values=[[0.2, 0.8], [0.7, 0.3]],
                               evidence=['Weather'], evidence_card=[2])
cpd_sprinkler = TabularCPD(variable='Sprinkler', variable_card=2,
                           values=[[0.6, 0.4], [0.3, 0.7]],
                           evidence=['Weather'], evidence_card=[2])

# 将条件概率分布添加到贝叶斯网络模型中
bayesian_network.add_cpds(cpd_weather, cpd_lawn_humidity, cpd_sprinkler)

# 创建变量消除推理对象
inference = VariableElimination(bayesian_network)

# 计算条件概率
result = inference.query(variables=['LawnHumidity'],
                         evidence={'Weather': 1, 'Sprinkler': 0})
print(result)

EM 算法

概述

**EM算法(Expectation-Maximization Algorithm)**是一种迭代优化算法,用于在含有隐变量的概率模型中估计参数。EM算法通过交替进行两个主要步骤:E步骤(Expectation Step)和M步骤(Maximization Step),以迭代地优化参数估计。

算法步骤:

  • E步骤(Expectation Step): 在这一步,算法通过当前参数估计计算隐变量的后验概率。

$$ Q(\theta | \theta^{(t)}) = E_{Z|X,\theta^{(t)}}[\log P(X, Z | \theta)] $$

  • M步骤(Maximization Step): 在这一步,算法通过最大化上一步中计算的后验概率的期望来更新参数估计。

$$ \theta^{(t+1)} = \arg\max_{\theta} Q(\theta | \theta^{(t)}) $$

EM算法通过交替执行E步骤和M步骤,迭代地优化参数估计,直到收敛。

import numpy as np
from scipy.stats import multivariate_normal

# 生成样本数据
np.random.seed(0)
X = np.concatenate([np.random.normal(0, 1, 100),
                    np.random.normal(5, 1, 100)])

# 初始化参数估计
mu = [1, 4]
sigma = [1, 1]
weights = [0.5, 0.5]

# EM算法迭代
n_iterations = 10
for _ in range(n_iterations):
    # E步骤:计算后验概率
    gamma = []
    for i in range(len(X)):
        likelihoods = [multivariate_normal.pdf(X[i], mean=mu[k], cov=sigma[k]) for k in range(len(mu))]
        weighted_likelihoods = [weights[k] * likelihoods[k] for k in range(len(mu))]
        total_likelihood = sum(weighted_likelihoods)
        gamma.append([weighted_likelihoods[k] / total_likelihood for k in range(len(mu))])

    # M步骤:最大化似然估计
    Nk = np.sum(gamma, axis=0)
    weights = [Nk[k] / len(X) for k in range(len(mu))]
    mu = [np.sum([gamma[i][k] * X[i] for i in range(len(X))]) / Nk[k] for k in range(len(mu))]
    sigma = [np.sqrt(np.sum([gamma[i][k] * (X[i] - mu[k]) ** 2 for i in range(len(X))]) / Nk[k]) for k in range(len(mu))]

print("Estimated weights:", weights)
print("Estimated means:", mu)
print("Estimated sigmas:", sigma)