zoukankan      html  css  js  c++  java
  • fisher线性分类器

    • Fisher准则函数

    Fisher准则的基本原理:找到一个最合适的投影轴,使两类样本在该轴上投影之间的距离尽可能远,而每一类样本的投影尽可能紧凑,从而使分类效果为最佳。

    假设有两类样本,分别为$X_1$和$X_2$

     则各类在d维特征空间里的样本均值为:

    $$M_i = frac{1}{n_i}sum_{x_kin X_i}x_k i=1,2$$

    通过$omega$变换后,将d维空间里的样本投影到一维。($y_k$是$x_k$通过$omega$变换后的标量)

    各类在1维特征空间里的样本均值为: 

    $$m_i=frac{1}{n_i}sum_{y_k in Y_i}y_k i=1,2$$

    各类样本类内离散度:

    $$s_i^2=sum_{y_k  in Y_i}(y_k-m_i)^2 i=1,2$$

    我们的目标是变换以后两类样本均值距离尽可能远并且每个样本尽可能聚在一起,即:

    $$max J_F(omega) = frac{(m_1-m_2)^2}{s_1^2+s_2^2}$$

    使$J_F$最大的$omega*$是最佳解向量,也就是Fisher的线性判别式

    • Fisher准则函数的求解

    $$y=omega^Tx$$

    $$m_i=frac{1}{n_i}sum_{x_k in X_i}omega^Tx_k=omega^TM_i$$

    $$(m_1-m_2)^2 = (omega^TM_1-omega^TM_2)^2$$

    $$= omega^T(M_1-M_2)(M_1-M_2)^Tomega = omega^TS_bomega$$

    原始维度下的类间离散度$S_b=(M_1-M_2)(M_1-M_2)^T$

    $S_b$表示两类均值向量之间的离散度大小

    $$s_1^2+s_2^2=sum_{x_k  in X_i}(omega^Tx_k-omega^TM_i)^2 i=1,2$$

    $$=omega^T · sum_{x_k in X_i}(x_k-M_i)(x_k-M_i)^T ·omega = omega^TS_womega$$

    样本"类内总离散度"矩阵$S_w= sum_{x_k in X_i}(x_k-M_i)(x_k-M_i)^T i=1,2$

    将上述推导结论代入$J_F(omega)$,得:$J_F(omega)=frac{omega^TS_bomega}{omega^TS_womega}$

    其中$S_b$和$S_w$都可以从样本集$X_i$直接计算出来

     用lagrange乘子法求解。令分母为常数$c=omega^TS_womega c eq0$

    $$L(omega,lambda)=omega^TS_bomega-lambda(omega^TS_womega-c)$$

    $$frac{partial L(omega,lambda)}{partialomega}=2(S_bomega-lambda S_womega)=0$$

    $omega$是法向量, 所以比例因子可以去掉。

    即$omega = S_w^{-1}(M_1-M-2)$ 

    阈值可以根据选择:

    $$b=-frac{1}{2}(m_1+m_2)=-frac{1}{2}(omega^TM_1+omega^Tm_2)$$

    参考代码:

      

    import matplotlib.pyplot as plt
    import numpy as np
    import random
    import math
    
    fig=plt.figure()#初始化figure对象
    ax=fig.add_subplot(111)#添加子图
    ax.set(xlim=[0,100],ylim=[0,100],title='Fisher criterion function')
    x1=np.zeros((2,100))
    x2=np.zeros((2,100))#新建2*100的矩阵用来保存数据
    for i in range(100):#随机生成第1类点
    	rd=random.uniform(0,25)#随机向量长度
    	rd2=random.uniform(-math.pi,math.pi)#随机向量方向
    	xlab=25+math.sin(rd2)*rd
    	ylab=75+math.cos(rd2)*rd#随机点的坐标
    	x1[0][i]=xlab
    	x1[1][i]=ylab#保存到x1中
    	ax.plot(xlab,ylab,color='red', marker='.')#图形化显示
    for i in range(100):#随机生成第2类点
    	rd=random.uniform(0,25)
    	rd2=random.uniform(-math.pi,math.pi)
    	xlab=75+math.sin(rd2)*rd
    	ylab=25+math.cos(rd2)*rd
    	x2[0][i]=xlab
    	x2[1][i]=ylab
    	ax.plot(xlab,ylab,color='blue', marker='.')
    
    M1=np.zeros(2)
    M2=np.zeros(2)
    for i in range(100):
    	for j in range(2):
    		M1[j]=M1[j]+0.01*x1[j][i]#求第一类点的重心
    
    for i in range(100):
    	for j in range(2):
    		M2[j]=M2[j]+0.01*x2[j][i]#求第二类点的重心
    
    ax.plot(M1[0],M1[1],color='black',marker='+',markersize=12)#将重心输出
    ax.plot(M2[0],M2[1],color='black',marker='+',markersize=12)
    
    Sw=np.zeros((2,2))#求总类内离散度矩阵Sw
    for i in range(100):
    	Sw=Sw+0.01*np.mat(x1[:,i]-M1).T*np.mat(x1[:,i]-M1)
    	+0.01*np.mat(x2[:,i]-M2).T*np.mat(x2[:,i]-M1)
    
    w=np.dot(np.linalg.pinv(Sw),(M1-M2))#求出方向向量
    w=np.mat(w.T)
    midPoint=(M1+M2)/2#阈值
    x=range(0,100)
    y=[]
    for i in range(100):
    	y.append(-float(w[0][0])/float(w[1][0])*(i-float(midPoint[0]))+float(midPoint[1]))
    #print(y)
    ax.plot(x,y,color='green',marker='*')
    
    plt.show()
    

    附:向量求导

    附:拉格朗日乘数法

    基本形态:求函数$z=f(x,y)$在满足$varphi(x,y)=0$条件下的极值,可以转化为函数$F(x,y,lambda)=f(x,y)+lambdavarphi(x,y)$的无条件极值问题,其中λ为参数。

    令$F(x,y,lambda)$对$x$和$y$和$lambda$的一阶偏导数等于零,即
    $$F'_x=ƒ'_x(x,y)+lambdavarphi'_x(x,y)=0$$
    $$F'_y=ƒ'_y(x,y)+lambdavarphi'_y(x,y)=0$$
    $$F'_{lambda}=varphi(x,y)=0$$
    由上述方程组解出$x$,$y$及$lambda$,如此求得的$(x,y)$,就是函数$z=ƒ(x,y)$在条件$varphi(x,y)=0$下的可能极值点。

  • 相关阅读:
    OC字符串处理
    用 map 表达互斥逻辑
    iOS之LLDB调试器
    iOS 线程安全 锁
    OC实现 单向链表
    iOS读取info.plist中的值
    SQLite 如何取出特定部分数据
    UIView常用的一些方法setNeedsDisplay和setNeedsLayout
    xCode常用快捷键
    oppo7.0系统手机(亲测有效)激活Xposed框架的流程
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/13734556.html
Copyright © 2011-2022 走看看