模式识别实验:最小错误率贝叶斯决策(单元多元都有涉及)


这个学期在学模式识别,把常见的算法本身手码出来了,感觉颇深,因此给你们分享一波

整个文章大纲html

  • 贝叶斯理论简介
    • 先验几率
    • 后验几率
  • 最小错误率贝叶斯决策
  • 最小风险贝叶斯决策

Part One 理论

1、贝叶斯理论简介

若是你是理工科出身,对贝叶斯公式确定不会陌生。
贝叶斯常常用于文档分类上,在电子邮件的过滤等文本处理上效果至关不错,最近题主在学校作的一个参加挑战杯的项目,是基于LDA贝叶斯模型,可能有些同窗会有点迷糊,这里的LDA不是Linear Discriminant Analysis线性分类器,是隐含狄利克雷分布(Latent Dirichlet Allocation)python

上贝叶斯公式:
p ( A B ) = p ( B A ) p ( A ) p ( B ) p(A|B) =\frac{p(B|A)\cdot p(A)}{ p(B)} git

话很少说,咱们来首先来看一下贝叶斯是基于什么样的思想:github

新信息出现以后A的几率 = A的几率×新信息带来的调整web

我在知乎上找到的维恩图很好地表现了贝叶斯公式的背后思想
bayers

来自非数学语言解释贝叶斯定理算法

那么如今对于最基础的公式有了最直观的理解以后,那咱们就能够学习怎么把这个思想运用到分类上。
咱们用先验几率和类条件几率的乘积,代替后验几率去作比较:
分类决策
其实很简单,我来举个例子
如今有2类硬币:
* 1元
* 0.5元
目前知道的有这两类硬币数量的比例,这是一个先验几率噢,好比说,为了简便,我取1:1,每一种类别的频率都为0.5
那么如今咱们想要根据测量硬币的重量来进一步预测这个硬币究竟是1元的仍是5角的
咱们就能够根据贝叶斯公式推算出未知硬币的分别属于哪一种硬币的几率,取几率大的为预测结果。
那你如今可能就会有问题了,后验几率怎么来的呢?
好问题,这也是贝叶斯的一个小bug,后验几率通常是根据数据得出,你能够看出其实这里不能作到彻底严谨。app

在通常应用中咱们假设这个特征在类内是服从正态分布的(实际上生活中不少特征都是这样的),正态分布由两个参数惟一决定,均值和方差。因此彻底能够用训练集中的特征的出现状况去估计这两个参数,从而获得类条件几率密度函数的模型。ide

  • 高斯分布:

    接下来咱们来学习什么是最小错误率贝叶斯决策

2、最小错误率贝叶斯决策

以下图,若是类条件几率密度函数和先验几率的乘积图像是这样的,那么在交点处做为分类面,对于特征的值x取在分类面左边的样本预测为红色类别,右边的样本预测为绿色类别,总的错误率最小:
图中一半阴影便是把绿色类误判为红色类的状况,一半阴影是把红色类误判为绿色类的状况。只有分类面取在交点处时这个错误率之和才能最小。
若是不是取在交点处,不论是在左边仍是右边,能够看到错误的面积老是会比刚刚那种状况多出一块:

如此咱们能够获得:
以二分类问题为例,对于样本x的决策错误率:

更进一步获得:

决策函数:

讨论多分类问题:
若是认为样本的特征向量在类内服从多元正态分布:

类条件几率密度服从多元正态分布,带入,得:svg

  • 多元正态分布
    p ( x ) = 1 ( 2 π ) 1 / 2 1 / 2 exp { 1 2 ( x μ ) T 1 ( x μ ) } , x R l p(x)=\frac{1}{(2\pi)^{1/2}|\sum|^{1/2}}\exp {\{-\frac{1}{2}(x-\mu)^T{\sum}^{-1}(x-\mu)\}}, \quad x \in R^l
  • mean均值
    μ = E [ x ] = E [ x 1 , x 2 , . . . . . , x l ] \mu = E[x] = E[x_1,x_2,.....,x_l]
  • 协方差矩阵:
    = E [ ( x μ ) ( x μ ) T ] = [ σ 11 2 σ 12 2 σ 1 l 2 σ 21 2 σ 22 2 σ 2 l 2 σ l 1 2 σ l 2 2 σ l l 2 ] \sum = E[(x-\mu)(x-\mu)^T]\\ = \begin{bmatrix} \sigma_{11}^2 & \sigma_{12}^2 & \cdots & \sigma_{1l}^2\\ \sigma_{21}^2 & \sigma_{22}^2 & \cdots & \sigma_{2l}^2\\ \vdots & \vdots & \ddots & \vdots\\ \sigma_{l1}^2 & \sigma_{l2}^2 & \cdots & \sigma_{ll}^2\\ \end{bmatrix}
  • 决策函数
    (0) g i j ( x ) = g i ( x ) g j ( x ) = 0 g_{ij}(x) = g_i(x) - g_j(x) = 0 \tag 0
    因为x符合正太分布,带入可得最终决策函数
    =>
    g i ( x ) = 1 2 l n   ( 2 π ) 1 2 l n   Σ i 1 2 ( x μ i ) T Σ i 1 ( x μ i ) + l n   p ( w i ) g_i(x) = -\frac{1}{2}ln \ (2\pi) - \frac{1}{2}ln \ |\Sigma_i| - \frac{1}{2}(x-\mu_i)^T\Sigma_i^{-1}(x-\mu_i) + ln \ p(w_i)
    这里题主采用了rev_gi,取了相反数,在比较大小的时候取最小值的决策函数就是咱们的最终结果的取值
    (1) r e v ( g i ) = g i ( x ) = 1 2 l n   ( 2 π ) + 1 2 l n   Σ i + 1 2 ( x μ i ) T Σ i 1 ( x μ i ) l n   p ( w i ) rev(g_i) = -g_i(x) = \frac{1}{2}ln \ (2\pi) + \frac{1}{2}ln \ |\Sigma_i| + \frac{1}{2}(x-\mu_i)^T\Sigma_i^{-1}(x-\mu_i) - ln \ p(w_i) \tag 1
    而根据决策面有
    g i j ( x ) = g i ( x ) g j ( x ) = 0 g_{ij}(x) = g_i(x) - g_j(x) = 0
    能够获得咱们的决策面:
    (2) 1 2 [ ( x μ i ) T Σ i 1 ( x μ i ) ( x μ j ) T Σ j 1 ( x μ j ) ] 1 2 l n   Σ i Σ j + l n   p ( w i ) p ( w j ) = 0 -\frac{1}{2}[(x-\mu_i)^T\Sigma_i^{-1}(x-\mu_i) - (x-\mu_j)^T\Sigma_j^{-1}(x-\mu_j)] - \frac{1}{2}ln \ \frac{|\Sigma_i|}{\Sigma_j} + ln \ \frac{p(w_i)}{p(w_j)} = 0 \tag 2

3、最小风险贝叶斯决策

码累了,下次补充函数

Part Two 实操

封装的算法是仿sklearn的风格。这里我用的accuracy_score直接调用sklearn的了,在后续的博客中(可能很慢,可是寒假来临后,会更新比较快,都是手码字,有些慢)
这段代码逻辑其实很清晰(某人自认为,不接受反驳!X^X)

  • 在init中一些必要的变量给加进去了,均值和协方差很重要!
  • Bayes中按状况传入先验几率,没传就计算出样本中各种的几率做为先验几率
  • 这里的decision_fuction实际上是为了画出模型的ROC曲线,而依据的公式是(0)公式,决策面以右方的0来决定,而如今画ROC取的阙值能够取这右边的值,也就是说,咱们能够取二者之差不为0的值做为新的决策阙值,来看模型在哪个取值上会有更好的效果
  • 在计算决策函数的时候,因为numpy的inv传入的值为1维(0维),会疯狂报错,因此这里须要对1个特征的进行特殊处理
import numpy as np
from numpy.linalg import inv
from sklearn.metrics import accuracy_score

class BayesGN:
    def __init__(self, priors=None):
        """初始化Linear Regression模型"""
        self.priors = priors
        self._mean = None
        self._cov = None

    def fit(self, X_train, y_train):
        """ sorted_y 和priors对应的类别序号相对应 """
        X_train = np.array(X_train)
        y_train = np.array(y_train)
        sorted_y = np.sort(np.unique(y_train))
        if self.priors is None:
            c = Counter(y_train)
            _sum = sum(c.values())
            self.priors = [c[y] / _sum for y in sorted_y]
        self._mean = [X_train[y_train == y].mean(axis=0) for y in sorted_y]
        self._cov = [np.cov(X_train[y_train == y].T) for y in sorted_y]
        return self

    def predict(self, X_predict):
        """给定带预测数据集X_predict,返回表示X_predict的结果向量"""
        y_predict = [self._predict(x) for x in X_predict]
        return np.array(y_predict)

    def _predict(self, Xi):
        return np.argsort(self._rvs_g(Xi))[0]

    def decision_function(self, X_test):
        b = [self._rvs_g(X_test[i])[0]-self._rvs_g(X_test[i])[1] for i in range(len(X_test))]
        return b

    def score(self, X_test, y_test):
        """根据数据集X_test,y_test计算准确度 分类准确度使用accuracy_score"""
        y_predict = self.predict(X_test)
        return accuracy_score(y_test, y_predict)

    def _rvs_g(self, Xi):
        if self._cov[0].ndim == 0:
            rvs_g = [(Xi - self._mean[i]) / self._cov[i] + np.log(self._cov[i]) - 2 * np.log(self.priors[i]) for i in
                     range(len(self._mean))]
        else:
            rvs_g = [np.matmul(np.matmul((Xi - self._mean[i]), inv(self._cov[i])),
                               (Xi - self._mean[i])) +
                     np.log(np.linalg.det(self._cov[i])) - 2 * np.log(self.priors[i]) for i in range(len(self._mean))]
        return rvs_g

使用真实数据实战!

  • 这里使用的数据来自参加上海大学模式识别中的历年男女学生的真实数据
  • 详情可见题主的Soledadzyh’s github

单特征

2个特征

  • 此处开始涉及parzen窗,题主下次再添加上相关资料

3特征