Fisher线性判别算法描述

在理解Fisher线性分类的参考代码基础上(matlab代码),改用python代码完成Fisher判别的推导。重点理解“群内离散度”(样本类内离散矩阵)、“群间离散度”(总类内离散矩阵)的概念和几何意义。

1、Fisher线性判别

Fisher线性判别分析的基本思想:选择一个投影方向(线性变换,线性组合),将高维问题降低到一维问题来解决,同时变换后的一维数据满足每一类内部的样本尽可能聚集在一起,不同类的样本相隔尽可能地远。
Fisher线性判别分析,就是通过给定的训练数据,确定投影方向W和阈值w0, 即确定线性判别函数,然后根据这个线性判别函数,对测试数据进行测试,得到测试数据的类别。
Fisher判别分析是要实现有最大的类间距离,以及最小的类内距离

在这里插入图片描述
线性判别函数的一般形式可表示成
g ( X ) = W T X + w 0 g(X)=W^TX+w_{0} g(X)=WTX+w0
其中
在这里插入图片描述
Fisher选择投影方向W的原则,即使原样本向量在该方向上的投影能兼顾类间分布尽可能分开,类内样本投影尽可能密集的要求。

(1)、W的确定

各类样本均值向量mi
在这里插入图片描述
样本类内离散度矩阵和总类内离散度矩阵Sw
在这里插入图片描述
在这里插入图片描述
样本类间离散度矩阵Sb
在这里插入图片描述
在投影后的一维空间中,各类样本均值
在这里插入图片描述
样本类内离散度和总类内离散度
在这里插入图片描述
样本类间离散度
在这里插入图片描述
Fisher准则函数为max
在这里插入图片描述

(2)、阈值的确定

是个常数,称为阈值权,对于两类问题的线性分类器可以采用下属决策规则:
在这里插入图片描述
如果g(x)>0,则决策x属于W1;如果g(x)<0,则决策x属于W2;如果g(x)=0,则可将x任意分到某一类,或拒绝。

(3)、Fisher线性判别的决策规则

1.投影后,各类样本内部尽可能密集,即总类内离散度越小越好。
2.投影后,各类样本尽可能离得远,即样本类间离散度越大越好。
根据这两个性质,可求出
在这里插入图片描述
这就是Fisher判别准则下的最优投影方向。最后得到决策规则,如果
在这里插入图片描述

在这里插入图片描述
对于某一个未知类别的样本向量x,如果y=WT·x>y0,则x∈w1;否则x∈w2。

(4)、“群内离散度”与“群间离散度”

“群内离散度”要求的是距离越远越好;而“群间离散度”的距离越近越好
由上可知:“群内离散度”(样本类内离散矩阵)的计算公式为
S i = ∑ x ∈ X i ( x − m i ) ( x − m i ) T S_i=\sum_{x∈X_i}(x-m_i)(x-m_i)^T Si=xXi(xmi)(xmi)T
因为每一个样本有多维数据,因此需要将每一维数据代入公式计算后最后在求和即可得到样本类内离散矩阵。存在多个样本,重复该计算公式即可算出每一个样本的类内离散矩阵
“群间离散度”(总体类离散度矩阵)的计算公式为
S w i j = S i + S j S_wij=S_i+S_j Swij=Si+Sj
例如鸢尾花数据集,会将其分为三个样本,因此就会得到三个总体类离散度矩阵,三个总体类离散度矩阵根据上述公式计算即可。

2、Python代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt 
import seaborn as sns
path=r'media/Iris.csv'
df = pd.read_csv(path, header=0)
Iris1=df.values[0:50,0:4]
Iris2=df.values[50:100,0:4]
Iris3=df.values[100:150,0:4]
m1=np.mean(Iris1,axis=0)
m2=np.mean(Iris2,axis=0)
m3=np.mean(Iris3,axis=0)
s1=np.zeros((4,4))
s2=np.zeros((4,4))
s3=np.zeros((4,4))
for i in range(0,30,1):
    a=Iris1[i,:]-m1
    a=np.array([a])
    b=a.T
    s1=s1+np.dot(b,a)    
for i in range(0,30,1):
    c=Iris2[i,:]-m2
    c=np.array([c])
    d=c.T
    s2=s2+np.dot(d,c) 
    #s2=s2+np.dot((Iris2[i,:]-m2).T,(Iris2[i,:]-m2))
for i in range(0,30,1):
    a=Iris3[i,:]-m3
    a=np.array([a])
    b=a.T
    s3=s3+np.dot(b,a) 
sw12=s1+s2
sw13=s1+s3
sw23=s2+s3
#投影方向
a=np.array([m1-m2])
sw12=np.array(sw12,dtype='float')
sw13=np.array(sw13,dtype='float')
sw23=np.array(sw23,dtype='float')
#判别函数以及T
#需要先将m1-m2转化成矩阵才能进行求其转置矩阵
a=m1-m2
a=np.array([a])
a=a.T
b=m1-m3
b=np.array([b])
b=b.T
c=m2-m3
c=np.array([c])
c=c.T
w12=(np.dot(np.linalg.inv(sw12),a)).T
w13=(np.dot(np.linalg.inv(sw13),b)).T
w23=(np.dot(np.linalg.inv(sw23),c)).T
#print(m1+m2) #1x4维度  invsw12 4x4维度  m1-m2 4x1维度
T12=-0.5*(np.dot(np.dot((m1+m2),np.linalg.inv(sw12)),a))
T13=-0.5*(np.dot(np.dot((m1+m3),np.linalg.inv(sw13)),b))
T23=-0.5*(np.dot(np.dot((m2+m3),np.linalg.inv(sw23)),c))
kind1=0
kind2=0
kind3=0
newiris1=[]
newiris2=[]
newiris3=[]
for i in range(30,49):
    x=Iris1[i,:]
    x=np.array([x])
    g12=np.dot(w12,x.T)+T12
    g13=np.dot(w13,x.T)+T13
    g23=np.dot(w23,x.T)+T23
    if g12>0 and g13>0:
        newiris1.extend(x)
        kind1=kind1+1
    elif g12<0 and g23>0:
        newiris2.extend(x)
    elif g13<0 and g23<0 :
        newiris3.extend(x)
#print(newiris1)
for i in range(30,49):
    x=Iris2[i,:]
    x=np.array([x])
    g12=np.dot(w12,x.T)+T12
    g13=np.dot(w13,x.T)+T13
    g23=np.dot(w23,x.T)+T23
    if g12>0 and g13>0:
        newiris1.extend(x)
    elif g12<0 and g23>0:
       
        newiris2.extend(x)
        kind2=kind2+1
    elif g13<0 and g23<0 :
        newiris3.extend(x)
for i in range(30,50):
    x=Iris3[i,:]
    x=np.array([x])
    g12=np.dot(w12,x.T)+T12
    g13=np.dot(w13,x.T)+T13
    g23=np.dot(w23,x.T)+T23
    if g12>0 and g13>0:
        newiris1.extend(x)
    elif g12<0 and g23>0:     
        newiris2.extend(x)
    elif g13<0 and g23<0 :
        newiris3.extend(x)
        kind3=kind3+1
correct=(kind1+kind2+kind3)/60
print("样本类内离散度矩阵S1:",s1,'\n')
print("样本类内离散度矩阵S2:",s2,'\n')
print("样本类内离散度矩阵S3:",s3,'\n')
print('-----------------------------------------------------------------------------------------------')
print("总体类内离散度矩阵Sw12:",sw12,'\n')
print("总体类内离散度矩阵Sw13:",sw13,'\n')
print("总体类内离散度矩阵Sw23:",sw23,'\n')
print('-----------------------------------------------------------------------------------------------')
print('判断出来的综合正确率:',correct*100,'%')

运行出来的结果“”
在这里插入图片描述
个人认为,Fisher判别比较复杂,但是Fisher判别又是最基本的线性判别方法之一,因此还是需要掌握其运用。除了Fisher判别,还有许多判别方法,例如贝叶斯、BP神经网络、K-means、决策树等线性判别,这几种方法,就我所知,决策树分类算法几行代码就能够计算出来准确率,比起上面复杂的Fisher判别方便许多!

以下是使用Python编程语言和NumPy库实现Fisher线性判别算法的示例代码: ```python import numpy as np class FisherLinearDiscriminant: def __init__(self, n_components): self.n_components = n_components self.w = None # 投影向量 def fit(self, X, y): # 计算每个类别的均值向量 class_means = [] for i in np.unique(y): class_means.append(np.mean(X[y == i], axis=0)) class_means = np.array(class_means) # 计算类内散度矩阵和类间散度矩阵 S_w = np.zeros((X.shape[1], X.shape[1])) S_b = np.zeros((X.shape[1], X.shape[1])) for i in np.unique(y): X_i = X[y == i] class_mean_i = class_means[i] S_w += np.dot((X_i - class_mean_i).T, (X_i - class_mean_i)) S_b += X_i.shape[0] * np.dot((class_mean_i - np.mean(X, axis=0)).reshape(-1, 1), (class_mean_i - np.mean(X, axis=0)).reshape(1, -1)) # 解决广义特征向量问题,得到最佳的投影方向 eig_vals, eig_vecs = np.linalg.eig(np.dot(np.linalg.inv(S_w), S_b)) eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:, i]) for i in range(len(eig_vals))] eig_pairs.sort(reverse=True, key=lambda x: x[0]) self.w = np.hstack([eig_pairs[i][1].reshape(-1, 1) for i in range(self.n_components)]) def transform(self, X): # 将数据投影到最佳方向上 return np.dot(X, self.w) def fit_transform(self, X, y): self.fit(X, y) return self.transform(X) ``` 在上述代码中,首先定义了一个FisherLinearDiscriminant类,其中包含了fit、transform和fit_transform三个方法,分别用于训练模型、将数据投影到最佳方向上和同时训练模型和将数据投影到最佳方向上。在fit方法中,计算了每个类别的均值向量、类内散度矩阵和类间散度矩阵,并解决了广义特征向量问题,得到最佳的投影方向。在transform方法中,将数据投影到最佳方向上。在fit_transform方法中,先调用fit方法训练模型,然后调用transform方法将数据投影到最佳方向上,并返回投影后的数据。 可以使用以下代码来测试FisherLinearDiscriminant类的功能: ```python from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 加载鸢尾花数据集 iris = load_iris() X = iris.data y = iris.target # 将数据集随机分成训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 使用Fisher线性判别进行降维 fld = FisherLinearDiscriminant(n_components=2) X_train_fld = fld.fit_transform(X_train, y_train) X_test_fld = fld.transform(X_test) # 训练逻辑回归模型 from sklearn.linear_model import LogisticRegression clf = LogisticRegression() clf.fit(X_train_fld, y_train) # 预测测试集的标签 y_pred = clf.predict(X_test_fld) # 计算模型的准确率 acc = accuracy_score(y_test, y_pred) print("Accuracy:", acc) ``` 在测试代码中,首先加载了鸢尾花数据集,并将数据集随机分成训练集和测试集。然后使用Fisher线性判别进行降维,将原始的4维数据降到2维。接着训练了一个逻辑回归模型,并使用测试集来评估模型的准确率。运行代码后,可以得到模型的准确率。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值