新普金娱乐网址


数学既然如此青春留不住

小儿不是一段时光数学,它实际是大家心灵最干净时对社会风气的一种感觉

取名的不二法门(clean code阅读笔记之一)

  • 二月 03, 2019
  • 数学
  • 没有评论

EM 算法

实则,下面仿照 K-means 算法的持筹握算步骤,就是 EM 算法的要旨部分了。

EM 算法主要分为 E 和 M 两步:

  1. E 指的是 Expectation,即统计均值的进程,对应的是地点的步调
    2,这一步关键是持筹握算每个样本归属的聚类中央;
  2. M 指的是 马克斯imum,即对参数的最大似然预计,对应的是下边的步子
    3。我眼前也说了,公式 (3) (4) (5)
    总计参数的公式是用最大似然函数推出去的,所以,这一步其实是在按照步骤
    2 的归类结果,重新用最大似然函数来推断参数。

上面那幅图是从西瓜书上截下来的,是 EM 算法求解 GMM 参数的一体化经过。

数学 1

图中有广大公式标记,可能要参考原书才看得懂,但是,它的流水线和我事先交付的
3
个步骤是一样。别的,算法的终止条件可以是达标最大迭代次数,或者是似然函数(公式
(2))的增高低于某个阈值。

好了,本文到那里就不再深远下去了。EM
算法博大精深,吴军先生在《数学之美》称它为上帝的算法,可知那个算法的强大之处。EM
算法能够应用的场子越发多,从本文给出的 GMM
例子来看,它事实上很类似梯度下跌算法,在加以的对象函数很复杂、难以求解时,EM
算法用一种迭代的策略来优化开首参数,并逐渐消失到最优解。关于那几个算法的具体内容,我想进一步深切精通后,再用一篇文章好好写一下。

14. 不用添加无意义的上下文

  • 作者提出尽量使用短的名字(在能清楚表明它意思的前提下)
  • 作者在那边举的悬空的上下文的例子有:在一个名为“Gas Station
    Deluxe”的主次中,所有的类都添加GSD的前缀,那样的上下文是抽象的(那里让我想到了Objective-C的GCD,哈哈)

自己的博客

那篇作品会不难提一下 GMM 模型的情节,最根本的,仍旧讲一下 EM
算法如何运用到 GMM 模型的参数估摸上。

其次章不难地罗列了一部分命名规则,大家在coding的时候会没完没了地对大家的变量、函数、参数、类、package,甚至源文件、和含有源文件的目录等等举办命名,那里是不难的几个命名规则能协助您更好地对那些命名。

K-means 的启示

在正儿八经开讲 EM 从前,大家先想起一下,K-means
是怎么求出聚类宗旨的。其实,总共分三步举行:

  1. 随意初步化 K 个聚类主题的地点;
  2. 将兼具样本点,根据跟各种聚类中央的相距进行分拣;
  3. 依照样本重新分类的结果,更新聚类中心的地点,重复步骤 2
    直到收敛(即聚类要旨再一次调整的增幅低于某个阈值)。

既然如此 GMM 本身也属于一种聚类算法,那么,我们能不可能用 K-means 的思绪来求出
GMM 的参数呢?答案当然是可以的。

只是,在那此前,大家须求先明了 GMM 的多少个参数(\(\pi_k\),\(\mu_k\),\(\Sigma_k\))要怎么计算。即使我们早就知晓了后验几率
\(P( x \in C_k|
x)\),则足以根据以下公式计算参数(其中,m 代表样本数量):
\[ \pi_k=\frac{1}{n}\sum_{i=1}^m{P(
x_i\in C_k|x_i)} \tag{3} \]
其一公式是把装有样本属于 \(C_k\)
的概率求平均后,作为 \(C_k\)
那一个聚类中央(或者说这么些高斯模型)的面世几率。
\[ \mu_k=\frac{\sum_{i=1}^m{
xP(x_i\in C_k|x_i)}}{\sum_{i=1}^m{P(x_i\in C_k|x_i)}} \tag{4}
\]
以此求均值的公式,跟单个高斯模型不一致的地点在于,大家用的是加权平均。因为每个样本点都有早晚的票房价值属于聚类焦点
\(C_k\),所以,每个样本对 \(C_k\)
对应的高斯模型的均值也会暴发一定的听从,只是由于 \(P(x_i\in C_k|x_i)\)
的值不一致,由此那种功效也会有众所周知差距。
\[
\Sigma_k=\frac{\sum_{i=1}^m{P(x_i\in
C_k|x_i)(x_i-\mu_k)(x_i-\mu_k)^T}}{\sum_{i=1}^m{P(x_i\in
C_k|x_i)}} \tag{5} \]
就如地,协方差也是用加权平均求出来的。

(公式 (3) (4) (5)
其实是从极大似然函数推出去的,在周志华先生的西瓜书PRML书中都有详尽推导,不过那里自己只想付出感性的认识)

可是,以上公式都是基于 \(P( x \in C_k|
x)=\frac{p(C_k)p( x| x\in C_k)}{p(
x)}\)总括出来的,而那几个公式本身又必要了然 \(P(C_k)\)(即 \(\pi_k\))等参数,那就沦为一个鸡生蛋依旧蛋生鸡的怪圈。

可是,借助 K-means 的思绪,大家得以先行随机开始化这个参数,然后总结出
\(P( x \in C_k| x)\),再用它立异GMM 参数,然后再用立异的模子计算 \(P( x \in
C_k| x)\),如此迭代下去,总有毁灭的时候,那样,我们不就足以像
K-means 一样统计出参数了吧?!

上面,大家就仿照 K-means 的法子,给出迭代划算 GMM 参数的步子:

  1. 随机初步化种种高斯模型的参数;
  2. 基于参数,计算 \(P( x \in C_k|
    x)\),这一步其实是计量出每一个样书归属于每一个聚类宗旨的票房价值;
  3. 按照第 2 步统计得到的 \(P( x \in C_k|
    x)\),根据公式 (3) (4) (5) 重新总计 GMM 参数,并再一次步骤 2
    直到收敛。

2. 避免传达错误的情致

  • 避免使用有歧义的名字,比如与其余已存的命名系统一样或一般的名字(比如hp,
    aix, sco)

  • 避免使用与语言特色相关的词,比如,accountList,
    要是它的确是一个或多或少语言中的List结构还好,倘使不是,最好使用bunchOfAccounts或者直接accounts更好。

  • 幸免在分化的地方采用唯有微妙区其余命名。比如你要花多长期才能分别一下五个变量:

      XYZControllerForEfficientHandlingOfStrings
      XYZControllerForEfficientStorageOfStrings
    
  • 选择相似的命名来表示相似的定义。这一条和上一条并不争辨,相似的概念应该运用相似但可以有分明的区分度的命名举办发挥。

  • 防止拔取外形上很不难导致误会的命名:比如大写的o和题诗的L,它们和0和1特意像,很难区分。

高斯混合模型

6. 防止发明新的编码方式来定名

  • 匈牙利(Magyarország)命名法:由于现代语言对于命名的尺寸已经远非界定,所以像匈牙利(Magyarország)命名法那种对命名举行二次编码的不二法门应该尽量防止使用

  • 前缀:很多言语应用前缀m_来标识那几个变量是一个分子变量,那种做法是没有意义的,程序的读者平常会一笑置之你的前缀而只关心后边的内容。别的,你的类和办法的概念范围应当丰盛小,让你不要求采取这一的前缀

      public class Part {
          private String m_dsc; // The textual description void setName(String name) {
              m_dsc = name; 
          }
      } 
    
      public class Part {
          String description;
          void setDescription(String description) {
              this.description = description; 
          }
      }
    
  • 接口和贯彻的命名:作者提出接口名尽量不要采用前缀,比如IShapeFactory作为接口,ShapeFactory作为落成类。应该防止让这一个接口的使用者看到给他拔取的是一个接口。

均值最大化算法 EM

4. 行使语音可读的命名

  • 一个好的命名应该是可读的,可读的命名能帮忙人更好领会代码,同时使人们更便于去探究这一个代码。
  • 尽量幸免使用genymdhms(generation date,year,
    month,打野,后人,minute,and
    second)那样很难读出来的命名,而使用generation提姆eStamp

GMM,即高斯混合模型(Gaussian Mixture
Model),简单地讲,就是将多少个高斯模型混合起来,作为一个新的模子,那样就足以概括运用多模型的表明能力。EM,指的是均值最大化算法(expectation-maximization),它是一种估算模型参数的政策,在
GMM 那类算法中应用广泛,因而,有时候人们又喜好把 GMM 那类可以用 EM
算法求解的模子称为 EM 算法家族。

3. 在命名和命名之间利用有意义的不一样

  • 譬如:在一段代码中要是急需运用多少个一般概念的变量时,尽量接纳有含义的章程来分别它们,防止使用a1、a2等变量命名。

  • 幸免选拔不需求的“噪音字”。一个类名叫Product比叫ProductInfo或者ProductData等好多了。

  • 幸免接纳冗余的’噪音字’。变量名中永远不应该包含单词variable;表名中应当永远不分包table。

  • 此地是一个荒唐的言传身教,那五个函数的命名完全是绝非意思的

      getActiveAccount(); 
      getActiveAccounts(); 
      getActiveAccountInfo();
    

数学 2

12. 用到描述难点的命名

  • 一经没有一个统计机专业名词来叙述您的章程或者变量,尽量保险你的命名能够清楚描述您的难题。

什么是 GMM

GMM 可以认为是 K-means 算法的升级版。在 K-means
中,大家会先总结出多少个聚类要旨,然后依照数据点与聚类主题的偏离,直接将数据点归类到近年来的聚类中央。那种做法实际上很“硬”,因为有不少边缘点属于七个聚类中央的几率恐怕离开不大,假诺一股脑就径直将它归到某一个为主,实在是太残忍了。而
GMM 分歧于 K-means
的地点就在于,它除了给出聚类焦点外,还是能告诉你各类点归属于某个聚类中央的概率,由此,GMM
又被称作 soft assignment。

首先,照旧提交 GMM 模型的公式:
\[ p( x)=\sum_{k=1}^K{\pi_k N(
x|\mu_k, \Sigma_k)} \]
其间,我们确定,\(\sum_{k=1}^K{\pi_k}=1\)。可以见见,GMM
就是将多少个高斯模型线性组合起来,人们习惯上把那之中的次第高斯模型称为
Component。其中,\(\pi_k\)
表示每个模型的占比,或者说数据属于模型 k
的几率,那一个值越大,表明聚集在那一个模型内的数码越来越多。

为何要用那种模型组合的法门啊?大家领悟,高斯模型相似成椭圆状(二维)或椭球状(三维),可以把这一个椭圆或椭球认为是一种聚类的形象,而圆心或球心则是聚类中央(对应高斯函数的参数
\(\mu\))。但真实世界中,数据的遍布并不一定都是按这样的模样分布的(如上边给出的图),因而,一个高斯模型可能无法很好的拟合这几个多少,而一旦能综合考虑多少个高斯模型的表达能力,让这一个模型发挥所长,不相同的模型拟合分化的多寡,那样一来,所有数据就可以很好地被这几个「组合模型」拟合起来。

其实,那种重组模型的思路可以应用到很多模型上,比如:泊松模型。而出于高斯模型本身一些不错的习性,因而GMM 那种模型被用的可比多。

眼前说到,GMM 本质上是一种聚类算法,那么,如果已知一个 GMM
模型,现在加以一个点,我们要怎么通晓那些点属于哪个聚类要旨呢?更具象一点说,怎么驾驭这么些点属于每个聚类中央的几率是稍稍?

用数学的语言表明就是,已知一个 GMM 模型: \(p( x)=\sum_{k=1}^K{\pi_k N( x|\mu_k,
\Sigma_k)}\),它的 K 个聚类主题为 \(C_k\),现在须求几率值 \(p( x \in C_k | x)\)。

求解的点子很简单,根据贝叶斯公式:\(p(a|b)=\frac{p(b|a)p(a)}{p(b)}\),大家得以汲取:
\[ p( x \in C_k | x)=\frac{p(C_k)p( x|
x\in C_k)}{p( x)} \]
于是,对于每个聚类中心 \(C_k\),由于分母 \(p( x)\) 都是千篇一律的,大家只需求总计 \(p(C_k)p( x| x\in C_k)=\pi_k N( x|\mu_k,
\Sigma_k)\数学,) 即可。获得的值就是数额点 $ x$ 属于 \(C_k\) 的票房价值,至于具体要将 $ x$
归类到哪个主题,能够依照具体情况决定,比如将几率最大的当作归属的聚类中央。那一点也是
GMM 优于 K-means
的地点,前者是因而概率的主意来支配归属,因而提供了越来越助长的信息。

8. 不用采纳可爱的命名

参考

13. 添加有意义的上下文

  • 写程序如同写文章,每一个艺术仍旧类都像一个段子,一些命名他们本身并不曾很强烈的意思,那么就须求把它置身一个有意义的内外文中,比如一个地方类Address,里边有一个属性是state,就肯定是标识州的意思,不过在其余上下文可能会有不一致的意义。

参数估量

不过,GMM 模型最难的地点在于,如何根据一堆数据点揣度出模型的参数?

GMM 必要规定的参数有三类:

  1. 高斯模型的个数 \(K\),那一个参数跟
    K-means 的 \(K\)
    一样,要求人工事先设定,\(K\)
    越大,聚类的粒度也越细;
  2. \(\pi_k\), 每个 Component
    的几率分量,或者说在总样本中的占比;
  3. \(\mu_k\)、\(\Sigma_k\),各个 Component 的参数。

若是样本所属分类已知(即已知 \(x\)
属于哪个 \(C_k\)),那 GMM
的参数就很不难确定了。首先,参数 \(K\)
就一目精通得到了。然后,借使样本容量为 \(N\),归属于聚类中央 \(C_k\) 的样本数量为 \(N_k\),归属每个 \(C_k\) 的样本集合为 \(S(k)\),可以用以下公式求出其他参数:
\[ \pi_k=\frac{N_k}{N} \\
\mu_k=\frac{1}{N_k}\sum_{ x\in S(k)}{ x} \\
\Sigma_k=\frac{1}{N_k}\sum_{ x\in S(k)}{( x-\mu_k)(
x-\mu_k)^T} \]
实质上,那跟一个高斯模型的事态是同等的,只可是要依葫芦画瓢求出 \(K\) 个。

但万一样本的归类事先不知底,又该咋做呢?首先,由于 \(K\)
这些值是亟需人工确定的,所以那边暂时即使 \(K\) 已经了解了。现在,大家要估量 \(K\) 个高斯模型的几率分量 \(\pi_k\) 以及各样模型各自的参数 \(\mu_k\) 和 \(\Sigma_k\)。

最简单易行也最不难想到的法子是巨大似然推断。如果有 m 个样本,首先,写出
\(p( x)=\sum_{k=1}^K{\pi_k N( x|\mu_k,
\Sigma_k)}\) 的似然函数:
\[ \begin{eqnarray} \ln{[\prod_{i=1}^m
p( x_i)]}&=&\ln{[\prod_{i=1}^m{\sum_{k=1}^K{\pi_k N(
x|\mu_k, \Sigma_k)}}]} \\
&=&\sum_{i=1}^m{\ln{[\sum_{k=1}^K{\pi_k N( x|\mu_k,
\Sigma_k)]}}} \\ \end{eqnarray} \]
而是,那个对数函数却出奇的复杂性,直接求导数的措施很难求出 \(\mu_k\) 和 \(\Sigma_k\),由此,大家只可以换用其余艺术来求解。而那就是
EM 算法发挥功用的地点。

9. 同一个概念使用同一个单词

  • 幸免在一个工程中使用fetch、get、retrieve等一般的单词来表达相同的情致。
  • 如出一辙的,还有不时使用到的Manager、Controller、Driver等。

5. 用到不难寻找的命名

  • 那条其实依旧说要接纳有意义的命名,比如一个变量MAX_CLASSES_PER_STUDENT是7,就不用把这一个变量的名字定
    义为SEVEN,那样更利于程序的读者去探寻。

  • 小编在那里写道,单个字母的变量名(i, j,
    k等)应该只好当做一个很短的主意的中间变量使用。

7. 防止脑补

  • 防止写出晦涩难懂的命名,比如在某处定义一个变量名为r,而只有写代码的人领悟这一个r代表的是url的小写方式。
  • 类名:类名应当是一个名词或名词短语,而不是动词
  • 艺术名:方法名应当是一个动词短语;当构造器需求重载时,尽量接纳分化命名的工厂方法,而不是选拔重载的不等参数的构造器(那点自己是持保留意见的)。

1. 应用名副其实(Intention-Revealing)的名字

  • 毫不定义无意义的名字

  • 决不采用magic numbers

  • 例子:

      // 坏代码例子
      public List<int[]> getThem() {
          List<int[]> list1 = new ArrayList<int[]>(); 
          for (int[] x : theList)
              if (x[0] == 4) list1.add(x);
          return list1; 
      }
    
      //不是很坏的代码
      public List<int[]> getFlaggedCells() {
          List<int[]> flaggedCells = new ArrayList<int[]>();
          for (int[] cell : gameBoard)
              if (cell[STATUS_VALUE] == FLAGGED) 
                  flaggedCells.add(cell);
          return flaggedCells;
      }
    
      //好代码
      public List<Cell> getFlaggedCells() {
          List<Cell> flaggedCells = new ArrayList<Cell>();
          for (Cell cell : gameBoard) 
              if (cell.isFlagged())
                  flaggedCells.add(cell); 
          return flaggedCells;
      }
    

11. 接纳程序员熟识的专盛名词

  • 不用害怕使用部分专有的计算机名词,比如算法,设计格局,数学名词等等。

正文是「Clean Code」(英文版)第二章的读书笔记。

10. 幸免选用双关语

  • 同一个单词在三个不等的现象下被利用,往往会导致误会,尤其是那二种现象下它们的意趣仍旧差别的。

相关文章

No Comments, Be The First!
近期评论
    分类目录
    功能
    网站地图xml地图