Python手撸机器学习系列(三):线性判别分析(Fisher究极详解,看不懂你锤死我)

1.原理概述

我们的目的是将高维的数据投影到一维直线上并在投影的值中取一个阈值进行分类,如下图所示:(绘画水平有限,将就着看)
请添加图片描述

在上图,很明显左边的投影更适合分类,因为两种类别(o和x)在投影直线上能轻松地找到一个阈值将其区分开来,而右边的投影方向则不适合当前分类。

所以我们需要求解一个适合的投影方向 w w w

在理解fisher的时候,我遇到了很多不理解问题,在经过多本书籍的对比之后终于搞懂了,其大致的思路如下:

  1. 问题的初衷在于找到一条线将坐标点向该线上投影,将这条线的方向设为 w w w,并用该 w w w作为假设带入,最后解出最佳 w w w
  2. 按照我们假设的 w w w,将样本点向该直线中投影,即 w T x w^Tx wTx,求出每一类样本点在投影上的均值和方差(或者说是协方差矩阵)
  3. 按照类间小,类内大的目标,设立目标函数求解 w w w

值得注意的是,我们求得的w是最终投影的平面(在这里为一维直线)方向,而不是感知机或逻辑斯蒂回归中的决策边界,这个问题一度让我以为自己的w求错了!!!

另外,在推导公式中,一定一定记得随时查看当前数据维度,不然极易混淆

2.原理详解

2.1 输入

对于样本点 X = ( x 1 , x 2 , . . . , x N ) T X = (x_1,x_2,...,x_N)^T X=(x1,x2,...,xN)T,其维度为 N × p N×p N×p,即每一个样本有 p p p个特征 ,其类别 Y = ( y 1 , y 2 , . . . , y N ) T Y = (y_1,y_2,...,y_N)^T Y=(y1,y2,...,yN)T,其中 y i ∈ { + 1 , − 1 } y_i\in\{+1,-1\} yi{+1,1}

我们将样本按其标签分为两类,数量分别为 N 1 N_1 N1 N 2 N_2 N2,即 ∣ x c 1 ∣ = N 1   ,   ∣ x c 2 ∣ = N 2   ,   N 1 + N 2 = N |x_{c1}|=N_1\ ,\ |x_{c2}| = N_2\ ,\ N_1+N_2 = N xc1=N1 , xc2=N2 , N1+N2=N

在本文中,我们用坐标点投影在直线上来直观地表述,即 p = 2 p=2 p=2

2.2 投影

假设,我是说假设啊,我们现在找到了一个适合的投影方向,则样本 x x x在直线 z z z上的投影为: z i = w T x i z_i = w^Tx_i zi=wTxi这个公式的来源:我们假设 w w w的模为1(因为方向重要长度不重要,可以缩放)。在两个向量中,你可以很明显地看出 x i x_i xi w w w上的投影为 Δ = x i c o s θ \Delta = x_icos\theta Δ=xicosθ,而 x i x_i xi w w w的点积为 x i ⋅ w = ∣ x i ∣ ∣ w ∣ c o s θ = ∣ x i ∣ c o s θ = Δ x_i·w = |x_i||w|cos\theta = |x_i|cos\theta = \Delta xiw=xiwcosθ=xicosθ=Δ,就是说我们可以用 x i x_i xi w w w的点积表示其 x i x_i xi w w w上的投影,写作 w T x i w^Tx_i wTxi的形式。

值得注意的是,在这里投影指的是 :以原点为起点, x i x_i xi为终点的向量在直线 z z z(方向为 w w w)上的投影

请添加图片描述

然后,所有样本在 z z z上的投影的均值为: z ˉ = 1 N ∑ i = 1 N z i = 1 N ∑ i = 1 N w T x i \bar z = \frac{1}{N}\displaystyle\sum_{i=1}^Nz_i=\frac{1}{N}\displaystyle\sum_{i=1}^Nw^Tx_i zˉ=N1i=1Nzi=N1i=1NwTxi

协方差(在这里可以理解为方差)为 S z = 1 N ∑ i = 1 N ( z i − z ˉ ) ( z i − z ˉ ) T = 1 N ∑ i = 1 N ( w T x i − z ˉ ) ( w T x i − z ˉ ) T S_z=\frac{1}{N}\displaystyle\sum_{i=1}^N(z_i-\bar z)(z_i-\bar z)^T=\frac{1}{N}\displaystyle\sum_{i=1}^N(w^Tx_i-\bar z)(w^Tx_i-\bar z)^T Sz=N1i=1N(zizˉ)(zizˉ)T=N1i=1N(wTxizˉ)(wTxizˉ)T

两个类分开写:

类别1: z 1 ˉ = 1 N 1 ∑ i = 1 N 1 w T x i \bar {z_1} = \frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}w^Tx_i z1ˉ=N11i=1N1wTxi S 1 = 1 N 1 ∑ i = 1 N 1 ( w T x i − z 1 ˉ ) ( w T x i − z 1 ˉ ) T S_1=\frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}(w^Tx_i-\bar {z_1})(w^Tx_i-\bar {z_1})^T S1=N11i=1N1(wTxiz1ˉ)(wTxiz1ˉ)T

类别2: z 2 ˉ = 1 N 2 ∑ i = 1 N 2 w T x i \bar {z_2} = \frac{1}{N_2}\displaystyle\sum_{i=1}^{N_2}w^Tx_i z2ˉ=N21i=1N2wTxi S 1 = 1 N 2 ∑ i = 1 N 2 ( w T x i − z 2 ˉ ) ( w T x i − z 2 ˉ ) T S_1=\frac{1}{N_2}\displaystyle\sum_{i=1}^{N_2}(w^Tx_i-\bar {z_2})(w^Tx_i-\bar {z_2})^T S1=N21i=1N2(wTxiz2ˉ)(wTxiz2ˉ)T

注意,这里由于我们是平面坐标点在一维直线上的投影,所以 z ˉ 、 S z 、 z 1 ˉ 、 z 2 ˉ 、 S 1 、 S 2 \bar z、S_z、\bar {z_1}、\bar{z_2}、S_1、S_2 zˉSzz1ˉz2ˉS1S2均可以理解为一个数。

还记得我们的目标吗:类内小,类间大

在这里,我们将类间表示为 ( z 1 ˉ − z 2 ˉ ) 2 (\bar{z_1}-\bar{z_2})^2 (z1ˉz2ˉ)2,即两个类别的样本分别取均值,其均值之差的平方

将类内表示为 S 1 + S 2 S_1+S_2 S1+S2,即两个类别的样本方差之和

由此我们可以很自然地得到一个最大化的目标函数:
J ( w ) = ( z 1 ˉ − z 2 ˉ ) 2 S 1 + S 2 J(w) = \frac{(\bar {z_1}-\bar{z_2})^2}{S_1+S_2} J(w)=S1+S2(z1ˉz2ˉ)2
极大化这个式子就相当于最小化 S 1 + S 2 S_1+S_2 S1+S2和最大化 ( z 1 ˉ − z 2 ˉ ) 2 (\bar {z_1}-\bar{z_2})^2 (z1ˉz2ˉ)2,完美符合我们的目标

对于 J ( w ) J(w) J(w),我们可以进一步的调整:

对于其分子:
( z 1 ˉ − z 2 ˉ ) 2 = [ 1 N 1 ∑ i = 1 N 1 w T x i − 1 N 2 ∑ i = 1 N 2 w T x i ] 2 = [ w T ( 1 N 1 ∑ i = 1 N 1 x i − 1 N 2 ∑ i = 1 N 2 x i ) ] 2 = [ w T ( x c 1 ˉ − x c 2 ˉ ) ] 2 = w T ( x c 1 ˉ − x c 2 ˉ ) ( x c 1 ˉ − x c 2 ˉ ) T w \begin{aligned} (\bar {z_1}-\bar{z_2})^2 &= \left[\frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}w^Tx_i - \frac{1}{N_2}\displaystyle\sum_{i=1}^{N_2}w^Tx_i \right]^2\\&=\left[w^T(\frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}x_i-\frac{1}{N_2}\displaystyle\sum_{i=1}^{N_2}x_i)\right]^2\\&=\left[w^T(\bar{x_{c1}}-\bar{x_{c2}})\right]^2\\&=w^T(\bar{x_{c1}}-\bar{x_{c2}})(\bar{x_{c1}}-\bar{x_{c2}})^Tw \end{aligned} (z1ˉz2ˉ)2=[N11i=1N1wTxiN21i=1N2wTxi]2=[wT(N11i=1N1xiN21i=1N2xi)]2=[wT(xc1ˉxc2ˉ)]2=wT(xc1ˉxc2ˉ)(xc1ˉxc2ˉ)Tw
对于其分母,我们先取 S 1 S1 S1进行分析:
S 1 = 1 N 1 ∑ i = 1 N 1 ( w T x i − z 1 ˉ ) ( w T x i − z 1 ˉ ) T = 1 N 1 ∑ i = 1 N 1 w T ( x i − x c 1 ˉ ) ( x i − x c 1 ˉ ) T w = w T 1 N 1 ∑ i = 1 N 1 ( x i − x c 1 ˉ ) ( x i − x c 1 ˉ ) T w = w T S c 1 w \begin{aligned} S_1 &=\frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}(w^Tx_i-\bar {z_1})(w^Tx_i-\bar {z_1})^T \\&= \frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}w^T(x_i-\bar{x_{c1}})(x_i-\bar{x_{c1}})^Tw \\&= w^T\frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}(x_i-\bar{x_{c1}})(x_i-\bar{x_{c1}})^Tw\\&=w^TS_{c1}w \end{aligned} S1=N11i=1N1(wTxiz1ˉ)(wTxiz1ˉ)T=N11i=1N1wT(xixc1ˉ)(xixc1ˉ)Tw=wTN11i=1N1(xixc1ˉ)(xixc1ˉ)Tw=wTSc1w
上式中我们用 S c 1 S_{c1} Sc1表示 1 N 1 ∑ i = 1 N 1 ( x i − x c 1 ˉ ) ( x i − x c 1 ˉ ) T \frac{1}{N_1}\displaystyle\sum_{i=1}^{N_1}(x_i-\bar{x_{c1}})(x_i-\bar{x_{c1}})^T N11i=1N1(xixc1ˉ)(xixc1ˉ)T,很显然,这个式子的意思为类别1中样本的方差

值得注意的是,这里的 S c 1 S_{c1} Sc1与之前的 S 1 S_1 S1有很大的不同!!!!!! S 1 S_1 S1表示的是投影的方差,维度1×1,在投影中可以理解为一个数!一个数!一个数!!!!而 S c 1 S_{c1} Sc1表示类别1样本的协方差矩阵,没有投影之前的协方差矩阵,维度为p×p,是一个矩阵!一个矩阵!一个矩阵!

这个地方一定要搞清楚,不然你就不知道为什么前面是方差是一个数但是后面方差求出来是一个矩阵了,我当时推了几遍才反应过来!

此外, p × p p×p p×p的协方差矩阵为 x i x_i xi的每一个特征的标准差与其他特征标准差的乘积

好了,书接上回:

S 2 S_2 S2同理,所以其分母等价于:
S 1 + S 2 = w T S c 1 w + w T S c 2 w = w T ( S c 1 + S c 2 ) w S_1+S_2 =w^TS_{c1}w + w^TS_{c2}w = w^T(S_{c1}+S_{c2})w S1+S2=wTSc1w+wTSc2w=wT(Sc1+Sc2)w

J ( w ) J(w) J(w)可以转化为:
J ( w ) = w T ( x c 1 ˉ − x c 2 ˉ ) ( x c 1 ˉ − x c 2 ˉ ) T w w T ( S c 1 + S c 2 ) w = w T S b w w T S w w J(w) = \frac{w^T(\bar{x_{c1}}-\bar{x_{c2}})(\bar{x_{c1}}-\bar{x_{c2}})^Tw}{ w^T(S_{c1}+S_{c2})w} = \frac{w^TS_bw}{w^TS_ww} J(w)=wT(Sc1+Sc2)wwT(xc1ˉxc2ˉ)(xc1ˉxc2ˉ)Tw=wTSwwwTSbw
我们用 S b S_b Sb表示 ( x c 1 ˉ − x c 2 ˉ ) ( x c 1 ˉ − x c 2 ˉ ) T (\bar{x_{c1}}-\bar{x_{c2}})(\bar{x_{c1}}-\bar{x_{c2}})^T (xc1ˉxc2ˉ)(xc1ˉxc2ˉ)T,其被称为类间方差

S w S_w Sw表示 S c 1 + S c 2 S_{c1}+S_{c2} Sc1+Sc2,其被称为类内方差

这里将 J ( w ) J(w) J(w)转化的意义在于,将原来假设的投影 w w w的方差和均值转化为了各类别样本本身的方差和均值,这样求解出来的w就可以直接用样本本来的值求解了,你甚至可以理解成把虚的变成实的!

2.3 求解 w w w

由上面的式子,可以得到:

J ( w ) = w T S b w w T S w w = w T S b w ⋅ ( w T S w w ) − 1 J(w) = \frac{w^TS_bw}{w^TS_ww} = w^TS_bw·(w^TS_ww)^{-1} J(w)=wTSwwwTSbw=wTSbw(wTSww)1

w w w进行求导并令结果为0:

∂ J ( w ) ∂ w = 2 S b w ⋅ ( w T S w w ) − 1 + w T S b w ⋅ ( − 1 ) ( w T S w w ) − 2 ⋅ 2 S w w = 0 \frac{\partial J(w)}{\partial w} = 2S_bw·(w^TS_ww)^{-1}+w^TS_bw·(-1)(w^TS_ww)^{-2}·2S_ww = 0 wJ(w)=2Sbw(wTSww)1+wTSbw(1)(wTSww)22Sww=0

两边同时乘上 ( w T S w w ) 2 (w^TS_ww)^2 (wTSww)2,注意这里 ( w T S w w ) (w^TS_ww) (wTSww)是一个数,维度计算: 1 × p   ⋅   p × p   ⋅   p × 1 = 1 × 1 1×p\ · \ p×p\ ·\ p×1 = 1×1 1×p  p×p  p×1=1×1

可得:
S b w ( w T S w w ) − w T S b w ⋅ S w w = 0 w T S b w ⋅ S w w = S b w ( w T S w w ) S_bw(w^TS_ww)-w^TSbw·S_ww = 0\\ w^TSbw·S_ww = S_bw(w^TS_ww) Sbw(wTSww)wTSbwSww=0wTSbwSww=Sbw(wTSww)
( w T S w w ) (w^TS_ww) (wTSww)一样, ( w T S b w ) (w^TS_bw) (wTSbw)依然是一个数,所以可得:
S w w = w T S w w w T S b w ⋅ S b ⋅ w S_ww = \frac{w^TS_ww}{w^TS_bw}·S_b·w Sww=wTSbwwTSwwSbw
两边左乘 S w − 1 S_w^{-1} Sw1,可得:
w = w T S w w w T S b w ⋅ S w − 1 ⋅ S b ⋅ w w =\frac{w^TS_ww}{w^TS_bw}·S_w^{-1}·S_b·w w=wTSbwwTSwwSw1Sbw
由于 w T S w w w T S b w \large \frac{w^TS_ww}{w^TS_bw} wTSbwwTSww是一个数,并不会影响我们求 w w w的方向,所以我们不妨设它为1(这里可以理解为我们投影的直线 z z z可以放缩),即可得:
w = S w − 1 ⋅ S b ⋅ w w = S_w^{-1}·S_b·w w=Sw1Sbw
我们继续研究,可以发现 S b ⋅ w = ( x c 1 ˉ − x c 2 ˉ ) ( x c 1 ˉ − x c 2 ˉ ) T ⋅ w S_b·w = (\bar{x_{c1}}-\bar{x_{c2}})(\bar{x_{c1}}-\bar{x_{c2}})^T·w Sbw=(xc1ˉxc2ˉ)(xc1ˉxc2ˉ)Tw,而 ( x c 1 ˉ − x c 2 ˉ ) T ⋅ w (\bar{x_{c1}}-\bar{x_{c2}})^T·w (xc1ˉxc2ˉ)Tw的维度计算为 1 × p ⋅ p × 1 = 1 × 1 1×p · p×1 = 1×1 1×pp×1=1×1,即实数,与 w w w方向无关。

所以最终我们求得的 w w w为:
w = S w − 1 ( x c 1 ˉ − x c 2 ˉ ) w = S_w^{-1}(\bar{x_{c1}}-\bar{x_{c2}}) w=Sw1(xc1ˉxc2ˉ)
即两个类协方差矩阵之和的逆矩阵乘上两个类的均值之差

3.代码实现

有了上述结果,我们可以很清楚的得到算法流程:

  1. 根据给定的两个类的样本,分别计算其协方差矩阵和样本均值
  2. 将协方差矩阵相加得到 S w S_w Sw,将样本均值相减得到 ( x c 1 ˉ − x c 2 ˉ ) (\bar{x_{c1}}-\bar{x_{c2}}) (xc1ˉxc2ˉ)
  3. 计算 w = S w − 1 ( x c 1 ˉ − x c 2 ˉ ) w = S_w^{-1}(\bar{x_{c1}}-\bar{x_{c2}}) w=Sw1(xc1ˉxc2ˉ)
  4. 将新样本根据计算出的 w w w投影,并进行分类

以下为python实现代码:

import numpy as np
import matplotlib.pyplot as plt

def fisher(x_1 , y_1 , x_2 ,y_2):

    #类内方差 Sw = S1 + S2
    u_1 = np.mean(x_1 , axis = 0 )
    S1 = (x_1 - u_1).T.dot((x_1-u_1))

    u_2 = np.mean(x_2 , axis = 0 )
    S2 = (x_2 - u_2).T.dot(x_2-u_2)

    Sw = S1 + S2
    # print(Sw)
    w = np.linalg.pinv(Sw).dot(u_1 - u_2) #inv逆矩阵,pinv伪逆矩阵

    return w

def predict(test_data , w , c1 , c2): #根据计算的W进行预测
    u_1 = np.mean(c1, axis=0)
    u_2 = np.mean(c2, axis=0)

    diff_1 = w.dot(u_1.T)
    diff_2 = w.dot(u_2.T)

    diff_cur = w.dot(test_data.T) #根据投影距离远近决定是哪一类

    return [1 if abs(diff_cur[i]-diff_1) < abs(diff_cur[i]-diff_2) else -1 for i in range(len(test_data))]

if __name__ == '__main__':
    X_True = [[1,1],[2,2],[0,4],[3,4]] #正例
    X_False = [[3,3],[4,5],[3,4],[5,4]] #负例
    Y_True = [1] * len(X_True)
    Y_False = [-1] * len(X_False)
    w = fisher(X_True,Y_True,X_False,Y_False) #求投影直线的方向w

    test_point = np.array([[2,5],[4,0]]) #测试数据
    predict_result = predict(test_point,w,X_True,X_False)
    print('测试点预测类别:'+str(predict_result))
    
    #绘图
    plot_x = np.arange(0,6)
    plot_y = -(w[0]*plot_x)/w[1]
    plt.scatter([x[0] for x in X_True] ,[x[1] for x in X_True] ,c = 'r',label = 'class 1')
    plt.scatter([x[0] for x in X_False] ,[x[1] for x in X_False] ,c = 'b',label = 'class -1')
    plt.scatter([x[0] for x in test_point] ,[x[1] for x in test_point] ,c = 'green',label = 'test_point')
    plt.plot(plot_x,plot_y,c = 'pink')
    plt.legend()
    plt.show()


运行结果:
在这里插入图片描述

图中的粉色直线即为所求结果,注意这个是投影的直线,而不是决策边界。

在这里插入图片描述

4.联系方式

如有问题欢迎评论区指出,有问题也可以联系我:
1759412770@qq.com

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锌a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值