简洁明了的搭建 PCA+LDA 仅公式无推导

网上关于机器学习算法的讲解很多,不过推导过程可能比较繁琐,结论比较隐蔽。为了能够让c/c++的初学者通过代码简单的实现、加深理解,所以本文章简单的总结出结论,尽量减少推导过程。并且将各个变量的范围、意义做出解释。

我目前大学本科在读,非人工智能专业,第一次接触机器学习,本文章仅是我的学习记录和总结,所有的处理方式都不一定是最正确的。但是致力于让只学完c\c++基本语法的人也能实现该算法。

不知道怎么处理数据、得到“输入”的请看我的文章:《机器学习数据的预处理》(如果找不到说明我还没写)。

另外,我会尽可能多打括号,防止各位对\sum到底对什么求和感到困惑,变量也用x[a]而非x_{a}表示,便于直接写成代码。

首先:

该算法的输入可以是连续的。另外,可以在预处理就使所有样本的同一个输入平均值为0,建议直接采用“标准化”。

矩阵类:

在c\c++编写pca和lda前,最好自己事先编写一个矩阵类,或者在网上找别人的代码实现矩阵运算。下面举例一个简单矩阵类,介绍所有需要的功能及变量:

 图中标出了所有变量,其意义如下:

1. width,矩阵宽度。显然是整型

2. depth,矩阵高度。显然是整型

3. m[a][b],矩阵第b行,第a个的值。是浮点型

需要的功能:

1. 矩阵乘矩阵,注意a*b矩阵乘以c*a矩阵将得到c*b矩阵

2. 矩阵乘\除常数,每项都乘上该常数

3. 矩阵加\减矩阵,各项相减

4. 矩阵转置,注意a*b会变成b*a

5. 矩阵求逆矩阵,尽量用高效的算法,否则高纬度的样本会使这一步非常非常慢。这里提供一种可行的方法,具体实现过于简单,不再赘述。将原矩阵M与一个单位矩阵变为增广矩阵

        \begin{Bmatrix} m[0][0] &m[1][0] &m[2][0] \\ m[0][1] &m[1][1] &m[2][1] \\ m[0][2] &m[1][2] &m[2][2] \\ 1 &0 &0 \\ 0&1 &0 \\ 0 &0 &1 \end{Bmatrix}

        ↓

经过初等变换,从左往右每一列减去左边几列对应值的x倍(图中及该x不表示某个具体值,仅表示该位置不为0,图中及该x与任一其他x不相等)

        \begin{Bmatrix} x &0 &0 \\ x &x &0 \\ x &x &x \\ 1 &x &x \\ 0&1 &x \\ 0 &0 &1 \end{Bmatrix}

        ↓

经过初等变换,从右往左每一列减去右边几列对应值的x倍

        \begin{Bmatrix} x &0 &0 \\ 0 &x &0 \\ 0 &0 &x \\ x &x &x \\ x &x &x \\ x &x &x \end{Bmatrix}

        ↓

        \begin{Bmatrix} 1 &0 &0 \\ 0&1 &0 \\ 0 &0 &1\\n[0][0] &n[1][0] &n[2][0] \\ n[0][1] &n[1][1] &n[2][1] \\ n[0][2] &n[1][2] &n[2][2] \end{Bmatrix}

截取下半部分作为矩阵N。N为M的逆矩阵。

PCA:

在了解下方的变量前,请确认:

1. 你有非常多的样本(即图中表示的非常多的点)

2. 你的每个样本有多个的输入的值(即每个点处于二维平面、三维或多维空间中)。

3. 如果已经过“标准化”则所有样本输入点的同个输入值平均值为0,换而言之,如果一个点以\left ( x,y,z,...... \right )^{T}表示的话,则样本里所有点的\overline{x}\overline{y}\overline{z}......都为0。如果没有经过标准化,请将所有点变成\left ( x-\overline{x},y-\overline{y},z-\overline{z},......\right )(很简单不说明方法)。

该算法将根据所有点的位置找到合适的投影方式为所有点降维(如图,将所有点降到1维似乎对点的分类没有帮助,可以将极高维的样本点降到合适(具体多少合适请因情况而异,具体下方会说明)的维度后,用lda实现分类,这也是为什么将pca与lda放在一起讲的原因)

所有变量,意义如下: 

1. K,你期望通过pca降到的维度。大于1但是小于等于输入样本点的维度,与lda结合使用时请多次尝试改变这个数值找到最优值。是整型

2. Mi,全部的输入样本。其中包含一个width(样本数量,即点的数量),一个depth(每个样本输入值的数量,即点的维度),in[a][b],第a个样本的第b维的值。是矩阵类(见上方矩阵类)

3. Ms,根据下方公式简单相乘得到的协方差矩阵,其width与depth符合矩阵相乘所得的宽与高。是矩阵类

4. Mtemp,输出的用于降维的矩阵。是矩阵类

5. Mo,输出的全部样本。其width与Mi的width相同,depth等于K。是矩阵类

学习:

1. 拷贝所有样本点到Mi中的in[a][b],并赋予Mi正确的width与depth。

2. 求协方差矩阵

        Ms=Mi*Mi^{T}

        (转置见上方矩阵类)

3. 用下方讲的 “qr分解” 方法求出Ms的所有特征值与特征向量,找出特征值最大的K个特征向量,纵向排列到Mtemp的in[a][b]中,请确认Mtemp的width等于K,Mtemp的depth等于Mi的depth

4. 得到输出的样本,显然样本的数量没有改变,还是width个,而样本的维度由depth维变成了K维

        Mo=Mtemp^{T}*Mi

得到结果:

因为是与LDA一起写,所以这里得到的结果有两个:

其一,是输出的Mo,作为lda的学习样本。

其二,是用于降维的矩阵Mtemp,在学习结束后用测试样本测试或投入使用时,直接用Mtemp^{T}乘以原始样本来降维原始样本。

LDA:

lda也是降维,我是这么理解的:pca的降维,是使所有点尽可能分散。lda的降维,是使不同类点尽可能分散,同类点尽可能集中。

另外,以下所有变量与pca里出现的变量并无关系,即使是重名也不是同一个变量,请注意。

所有变量,意义如下: 

1. K,你期望通过lda降到的维度。小于等于输入样本点的维度,且可以等于1。是整型

2. Mi,全部的输入样本,拷贝自pca的Mo。是矩阵类

3. num_o,答案的种数。显然是整型

4. o[a],第a个样本所对应的答案。是整型

5. num_x[a],答案为a的样本的个数。显然是整型

6. x[a][b],答案为a的第b个样本。其width等于1,其depth等于Mi的depth。是矩阵类

7. μ[a],答案为a的所有样本各个值的平均值。其width等于1,depth等于Mi的depth。是矩阵类

8. Msw,类内协方差矩阵。是矩阵类

9. Msb,类间协方差矩阵。是矩阵类

10. Mtemp,输出的用于降维或得到答案的矩阵。是矩阵类

学习:

1. 拷贝pca的Mo到这里的Mi,拷贝输入样本的所有答案到o[a],显然经过pca的变换不会影响样本的顺序,所以答案也按原来的顺序拷贝即可。

2. 将Mi中所有答案不同的样本分别拷贝到Mi[a][b]中。并计算μ[a]:

        \mu [a]=\frac{\sum_{k=0}^{num\underline{\: }x[a]}(x[a][k])}{num\underline{\: }x[a]}

3. 计算类内协方差矩阵。

        Msw=\sum_{l=0}^{okind}[\sum_{k=0}^{num\underline{\: }x[l]}(x[l][k]-\mu [l])*(x[l][k]-\mu [l])^{T}]

        (公式中是 x*x^{T} 还是 x^{T}*x 取决于你的x[a][b]是竖着的还是躺着的。如果严格按照上文方法定义该矩阵就应该使用 x*x^{T} ) 

3. 计算类间协方差矩阵

        Msb=\sum_{k=0}^{okind}(P\left \{ o=k \right \}*\mu [k]*\mu [k]^{T})

        (P{o=k}即o[a]=k的概率,计算非常简单,不多介绍)

4. 用上方讲的 “qr分解” 方法求出矩阵 “ Msw^{-1}*Msb ” (如果程序卡住可能是矩阵求逆过慢)的所有特征值与特征向量,找出特征值最大的K个特征向量,纵向排列到Mtemp的in[a][b]中,请确认Mtemp的width等于K,Mtemp的depth等于Mi的depth

输出的结果:

注意pca的Mtemp与lda的Mtemp需要作为学习结果保存。

1. 如果K=1,则用Mtemp^{T}乘以样本可以使所有点最终降到1维:\left ( x \right ),每一类点都可以得到一个\left ( \overline{x} \right ),这些 \overline{x} 可以作为学习结果保存。则测试或投入使用时,得到样本点Input,可以通过计算:

        x=\underset{pca}{Mtemp}*\underset{lda}{Mtemp}*Input

再将 x 与每一类的 \overline{x} ,比较大小,最接近的一项作为答案输出。

2. 如果K>1,则可以得到:

        Mo=Mtemp^{T}*Mi

像数据经过pca处理再传递到lda一样,lda可以再将处理完的样本传递至下一步处理。

QR分解求特征值及特征向量:

为什么放到下面讲,因为就针对我自己而言,这个东西是最劝退的,当然如果网上找到的矩阵类中包含求特征值与特征向量的方法,则可以跳过这个直接结束。

需要的变量:

1. N,迭代次数,越大越准确(我做测试时取的是50,可供参考)。显然是整型

2. A,原矩阵,即需要求特征值与特征向量的矩阵。是矩阵类

3. B[a],第a次迭代准备被分解的矩阵。是矩阵类

4. Q[a],第a次迭代分解出的Q矩阵。是矩阵类

5. R[a],第a次迭代分解出的R矩阵。是矩阵类

6. λ[a],输出的所有特征值。是浮点型

7. O,输出的矩阵,每一列是A的一个特征向量。是矩阵类

qr分解及迭代:

1. 拷贝原矩阵即A到B[0]。

2. 如下方式分解B[0]得到Q、R。先申请几个临时变量

        1. q[a]。是矩阵类

        2. r[a]。是矩阵类

        3. temp[a],用于将向量单位化。是浮点型

先将B[0]分解为width个宽度为1,高度为depth的矩阵(向量)q。

        \begin{Bmatrix} x & x & x\\ x & x & x\\ x & x & x \end{Bmatrix}

        ↓

        \begin{Bmatrix} x\\x\\x \end{Bmatrix} \begin{Bmatrix} x\\x\\x \end{Bmatrix} \begin{Bmatrix} x\\x\\x \end{Bmatrix}(如图所示,一个3*3矩阵被分为3个1*3矩阵:q[0]、q[1]、q[2])

将一个单位矩阵分解为width个宽度为1,高度为depth的矩阵(向量)r。

        \begin{Bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{Bmatrix}

        ↓

        \begin{Bmatrix} 1\\0\\0 \end{Bmatrix} \begin{Bmatrix} 0\\1\\0 \end{Bmatrix} \begin{Bmatrix} 0\\0\\1 \end{Bmatrix}(如图所示,一个3*3矩阵被分为3个1*3矩阵:r[0]、r[1]、r[2])

从0到a按顺序求出每个q[a]、r[a](注意这不是严谨的数学公式),每个

        \left\{\begin{matrix} r[a]-=\sum_{K=1}^{a}(\frac{q[k]^{T}*q[a]}{q[a]^{T}*q[a]}*r[k]) \\ q[a]-=\sum_{K=1}^{a}(\frac{q[k]^{T}*q[a]}{q[a]^{T}*q[a]}*q[k]) \end{matrix}\right.         

        (a>0)

此时,计算出所有temp[a]。

        temp[a]=\sqrt{\left |q[a]^{T}*q[a] \right |}

按顺序合并并处理Q[0]、R[0]:

        Q[0]=\{ \frac{q[0]}{temp[0]}|\frac{q[1]}{temp[1]}|\frac{q[2]}{temp[2]}|...... \}

        R[0]=\{ \frac{r[0]}{temp[0]}|\frac{r[1]}{temp[1]}|\frac{r[2]}{temp[2]}|...... \}^{-1}

3. 按照分解B[0]的方式,如下迭代N次,第a次迭代时:

        B[a]->Q[a],R[a]

        B[a+1]=R[a]*Q[a]

        最终得到B[N],形如:

        \begin{Bmatrix} \lambda[0] & x & x&......\\ 0 & \lambda[1] & x\\ 0& 0 & \lambda[2]\\ ...... \end{Bmatrix}

        其对角线上各值即为特征向量。拷贝到λ[a]中。

4. 对于每个λ[a],得到A-λ[a],形如:

        \begin{Bmatrix} x-\lambda [a] & x & x&......\\ x & x-\lambda [a] & x\\ x & x & x-\lambda [a]\\ ...... \end{Bmatrix}

最右增加一列0,形如:

        \begin{Bmatrix} x-\lambda [a] & x & x&......&0\\ x & x-\lambda [a] & x&&0\\ x & x & x-\lambda [a]&&0 \\......&&&&...... \end{Bmatrix}

将任意一行,比如第一行变成{1,0,0,......,1}(原因不解释),形如:

        \begin{Bmatrix} 1&0&0&......&1\\ x & x-\lambda [a] & x&&0\\ x & x & x-\lambda [a]&&0 \\......&&&&...... \end{Bmatrix}

最后做行初等变换使之形如:

        \begin{Bmatrix} 1&0&0&0&......&a\\ 0& 1 & 0&0&......&b\\ 0 & 0 & 1&0&&c\\ 0 & 0 & 0 &1&&d \\......&&&&&...... \end{Bmatrix}

取最后一列\{a,b,c,d,......\}^{T}即为该λ[a]对应的特征向量,将所有这些向量按顺序填入到O中,与λ[a]一起作为输出。

最后:

写的比较匆忙,很多地方没有检查,我本人学习这些算法的时间也很短,如果存在任何问题,有任何意见或建议欢迎指出,我会马上进行更正。

另外,要深入理解一种算法,其具体原理和推导过程也是需要学习的。网上有太多这方面的文章,在这就不做详细解释。

谢谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值