21/8/14 读书笔记 防御式编程 贝叶斯分类器
读书笔记
Code Complete 防御式编程
防御式编程的基本思想在于子程序不应该因为传入错误的数据而被破坏,哪怕错误数据来自于其他错误程序。
用错误处理代码处理可预知的情况,用断言处理不可预知的情况。
断言用于软件的维护和开发阶段,当进入产品时应该删掉以提高性能,因此避免将需要执行的代码放在断言里。
断言用于验证子程序的前条件和后条件,是契约式编程的支撑部分。
错误处理的核心在于平衡正确性和健壮性,据此对可预期的错误进行不同形式的处理:
- 正确性:子程序对逻辑永远忠诚,永不返回错误的结果,即使不返回任何结果。
- 健壮性:子程序容忍一些不够准确的结果,以使得软件能够持续运行。
异常机制的应用情境和断言类似,都是处理(对被调用的子程序而言)罕见甚至不应该发生的情况,且该情况在被调用的子程序局部无法解决。
异常的本质还是错误处理技术,其表示发生异常的子程序无法处理该异常,因此返回异常使得调用者进行处理。大多数编程语言支持异常机制,但是我们不应该为了使用异常而使用异常,而是应该根据错误处理技术对于正确性和平衡性的考虑来选择合适的错误处理方式。
异常需要调用者知晓被调用者抛出的异常类型,因此弱化了封装性。
一个子程序所抛出的异常应该和该层次的抽象相契合,即需要对低层次的异常进行包装以保持封装性,不因为返回的异常而暴露自身的实现。
隔栏(barricade)是一种容损策略,其在系统结构中设立边界,边界的一边是安全区域,安全区域中的数据在预期中都应该是正确的。隔栏需要在安全区域的边界上对数据进行合法性校验和清洗,安全区域外的数据会引发可预期的错误,而安全区域内的数据在可预期的范围内不应该引发错误。这使得我们能在安全区域内假定所有数据都是安全的,无需承担错误处理的职责。
隔栏很好地区分了错误处理和断言的使用场景。安全区域内使用断言,因为只会出现不可预期的错误,在产品期移除;安全区域外使用错误处理技术,并在产品期适当保留以供后续维护。
进攻式编程是一种尽可能让错误在开发阶段就暴露出来的技术,其核心思想是在开发阶段尽可能地恶化软件的工作环境。比如在删除一个对象前将其塞满垃圾数据、完全填充自己分配到的所有内存等,以使得程序在可能出现的最恶劣的情况下运行,同时对发生的错误进行记录和处理。进攻式编程使得错误难以被忽视。
机器学习 贝叶斯分类器
贝叶斯分类器(Bayes Classifier)和一般意义上的贝叶斯学习(Bayesian Learning)有显著差异,前者注重利用最大后验概率进行单点估计,后者则是进行分布估计。
对于一个判定准则\(H\),基于后验概率可以计算将样本分类错误所造成的期望损失,称为该准则的条件风险。所有样本的总条件风险称为该准则的总体风险。贝叶斯判定准则要求在每个样本上选择能使条件风险最小的类别标记,以最小化总体风险。满足条件的准则\(H\)称为贝叶斯最优分类器,其描述了机器学习所能达到的模型精度的理论上限。
后验概率\(P(y_j|\bold x)\),即对于属性集\(\bold x\),准则将其误分类为\(y_j\)的概率。由于这个概率难以直接获得,因此机器学习的目标是为了基于有限的训练样本尽可能进行估计。机器学习方法因此分为两种:
- 判别式模型:直接对后验概率进行建模来预测。决策树、BP神经网络、SVM等均属于判别式。
- 生成式模型:对联合概率分布\(P(\bold x,y)\)建模,而后获得后验概率。
对于生成式模型,我们基于贝叶斯定理可以得出:
其中:
- \(P(y)\)为先验概率,描述\(y\)这个类别标记的出现概率。可以通过各种样本的出现频率进行估计。
- \(P(\bold x|y)\)是样本x相对类标记y的类条件概率,也称为似然。由于属性组合的可能性空间比类别空间大很多,因此我们不能直接根据样本的支持度来进行估计。
- \(P(\bold x)\)是证据因子,用于归一化,与类别标记无关。
为了估计似然,我们通常先假定其具有某种概率分布形式,然后基于训练样本对其概率分布的参数进行估计。其中常用的方法是极大似然估计,以寻找最大化似然的参数值为目标。这种参数化的方法极大依赖于我们对似然概率分布的假设是否正确。
朴素贝叶斯分类器进行了属性条件独立性假设,即所有属性相互独立。在此基础上认为\(P(\bold x)=\prod_{i=1}^k P(x_i)\),由此将属性组合\(\bold x=\{x_1,x_2,...\}\)拆开成单个的属性\(x_i\)来进行考虑其条件概率,避免了样本由于特定属性组合出现概率低而带来的问题。但是这样如果属性\(x_i\)上的属性值\(a\)在样本中没有出现,那么任何包括\(x_i=a\)的属性组合的概率就都是0,这使得\(x_i\)以外的其他属性携带的信息被忽略了。因此需要在计算概率时进行“平滑”处理,常用的是拉普拉斯修正,避免了训练样本不充分带来的概率估值为零的问题。
半朴素贝叶斯分类器认为适当考虑一部分属性间的依赖关系,常用的策略是独依赖估计,即只考虑每个属性最多只依赖一个其他属性。根据如何确定每个属性的父属性,不同的做法对应不同的独依赖分类器。如果我们进一步放松依赖关系的限制到更高阶的依赖,则也许能获得泛化性能提升,但是所需的样本数呈指数级增加。
贝叶斯网络借助有向无环图来描述属性间的依赖关系,因此表示任何属性间的依赖性。其中可能出现三种典型依赖关系:
- 同父结构:属性\(x_1\)和\(x_2\)的父结点都是\(x_3\)。如果\(x_3\)给定,那么\(x_1\)和\(x_2\)相对独立。
- V型结构:属性\(x_1\)和\(x_2\)的子结点都是\(x_3\)。如果\(x_3\)给定,那么\(x_1\)和\(x_2\)必然不独立。如果\(x_3\)完全未知,那么\(x_1\)和\(x_2\)相对独立。这种独立性称为边际独立性。
- 顺序结构:属性\(x_1\)依赖\(x_2\),\(x_2\)依赖\(x_3\)。
为了找到条件独立性,最快最直观的方法就是将网络结构转换为“道德图”并进行道德化。
寻求最优贝叶斯网络结构的目标是最小描述长度,依赖评分函数对网络与数据的契合程度进行评价,不同的评分函数表现了不同的归纳偏好。这是一个NP难问题,因此常用的策略是通过贪心法不断尝试调整直到评分函数不再更优,或者限制网络结构满足特定约束,比如限定网络为树形结构。
建立贝叶斯网络后,我们最理想的方法是直接从联合概率分布精准推断后验概率,但是理论证明这是NP难的。需要借助近似推断,通常采用吉布斯采样来完成。吉布斯采样实际依赖一个马尔科夫过程,如果贝叶斯网络存在极端概率0或者1,那么马尔科夫链不一定平稳分布,吉布斯采样将会得出错误结果。
隐变量,指未观测变量。EM算法是常用的用于估计参数隐变量的迭代式方法。其交替进行下列步骤:
- 已知参数\(\theta^i\),根据训练样本计算最优隐变量\(Z\)的值
- 已知\(Z\)的值,对参数\(\theta\)进行最大似然估计,得到\(\theta^{i+1}\)
EM算法是梯度下降法等算法以外的一种非梯度优化方法。

浙公网安备 33010602011771号