# fisher
**Repository Path**: ranchongzhi/fisher
## Basic Information
- **Project Name**: fisher
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-01-24
- **Last Updated**: 2021-01-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## Fisher线性判别+KNN算法分类
### 环境
- pycharm专业版2019.3.3
- python3.7.4
- 外部库:numpy=1.16.5;sklearn=0.21.3;matplotlib=3.3.1;openpyxl=3.0.0
### 原理简介
将一个一个复杂的高维分类问题,先通过fisher线性判别分析进行降维,降到低纬之后,再通过KNN算法进行分类
### 一些计算公式
#### 在n维X空间
- 各类样本均值向量$\mu_{i}$:
$$
\mu_{i}=\dfrac{1}{N_{i}}\sum_{x_{j}\in\Omega_{i}}x_{j},i=1,2
$$
- 各类类内离散度矩阵$S_{i}$:
$$
S_{i}=\sum_{x_{j}\in\Omega_{i}}\left( x_{j}-\mu_{i}\right) \left( x_{j}-\mu_{i}\right) ^{T},i=1,2
$$
- 总类内离散度矩阵$S_{w}$:
$$
S_{w}=\sum_{x_{j}\in \Omega_{i}}S_{i},i=1,2
$$
- 二分类情况下样本类间离散度矩阵$S_{b}$:
$$
S_{b}=(\mu_{1}-\mu_{2})(\mu_{1}-\mu_{2})^{T}
$$
- 多分类情况下的样本类间离散度矩阵$S_b$:
$$
S_b=\sum_{i=1,2,...c}{N_i}(\mu_i-\mu)(\mu_i-\mu)^{T}
$$
其中$\mu$是所有样本的均值
#### Y空间
- 各类样本均值$\overline{\mu_{i}}$:
$$
\overline{\mu_{i}}=\dfrac{1}{N_{i}}\sum_{y_{j}\in \psi_{i}}y_{j},i=1,2
$$
- 各类内离散度$\overline{S^2_{i}}$:
$$
\overline{S_{i}}^{2}=\sum_{y_{j}\in \psi_{i}}\left( y_{j}-\overline\mu_{i}\right)^{2},i=1,2
$$
- 二分类情况下降到一维最佳投影方向$\omega^\*$:
$$
\omega^\*=S_\omega^-1(\mu_{1}-\mu_{2})
$$
- 降到二维的最佳投影方向${\omega}^\*$:
$$
S_{w}^{-1}S_{b}\omega^\*=\lambda\omega^\* (9)
$$
根据式子(9)计算出特征值$\lambda$,取最大的前两个特征值所对应的特征向量,将其组合在一起,即为所求的最佳投影方向,式(9)中的$S_b$由式(5)计算得来
#### 评价指标
- 总体分类精度OA:
$$
\frac{所有判断正确的样本数}{所有测试样本数}\times100\%
$$
- 类别分类精度AA:
$$
\frac{某一类中判断正确的样本数}{该类参与测试的样本数}\times100\%
$$
- kappa系数:
$$
\frac{OA-pe}{1-pe}
$$
- pe:
$$
\frac{\sum{(某类参与测试的样本数\times{被判断为该类的测试样本数})}}{所有的测试样本数^2}
$$
### 数据标准化
由于两种数据集中特征的量纲都一样,所以为了消除量纲,将每个特征的数值除以该特征中的最大值即可,这样将所有特征数值映射到了区间[0,1]之间
### 划分训练集和测试集
利用sklearn包中的train_test_split函数进行训练集和测试集的划分,其中训练集占比40%,测试集占比60%。
其中train_test_split函数的一般形式如下:
```python
X_train,X_test, y_train, y_test =train_test_split(train_data,train_target,test_size=0.4, random_state=0)
```
参数解释:
- train_data:所要划分的样本特征集
- train_target:所要划分的样本结果集
- test_size:测试样本占比,如果是整数的话就是样本的数量
- random_state:是随机数的种子
- 随机种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数
通过该函数,只要每次传入不同的随机种子,就可以得到不同的训练集、测试集
### 分类策略
1. sonar数据集
sonar数据集为一个二分类问题,只需要计算出最优投影方向,投影后:
- 方案一:将样本降到一维,计算出决策点,再进行分类
- 方案二:将样本降到2维,通过KNN算法进行分类
2. iris数据集
iris数据集为一个三分类问题
- 方案一:可以将其转化为三个二分类问题进行分类,具体分类思路如下:

- 方案二:将样本降到二维,再通过KNN算法进行分类
### K值的选择
KNN分类算法中,需要我们提前指定k的值,本次试验的k值选取过程如下:
- 先构建好分类器
- 对于iris数据集,k分别取值为$4,5,7,8,10,11,13,14,16,17,19,20,22,23$,求出对应的OA值,取最大的OA值对应的k值为最终的k值
- 对于sonar数据集,k分别取值为$3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35$,求出对应的OA值,取最大的OA值对应的k值为最终的k值
得到的结果如下:
- sonar:
- iris:
由上图可知,两数据集都取**k=5**分类效果最好
### 分类结果展示
#### sonar数据集
1. **分类方案1:**
| 试验次数 | 整体分类精度OA | kappa系数 | 第一类类别分类精度AA | 第二类类别分类精度AA |
| :--------: | :------------: | :-------: | :------------------: | :------------------: |
| 1 | 0.603 | 0.213 | 0.678 | 0.537 |
| 2 | 0.690 | 0.370 | 0.559 | 0.806 |
| 3 | 0.690 | 0.380 | 0.695 | 0.687 |
| 4 | 0.587 | 0.171 | 0.559 | 0.612 |
| 5 | 0.690 | 0.385 | 0.763 | 0.627 |
| 6 | 0.698 | 0.389 | 0.610 | 0.776 |
| 7 | 0.675 | 0.355 | 0.763 | 0.597 |
| 8 | 0.683 | 0.371 | 0.780 | 0.597 |
| 9 | 0.706 | 0.410 | 0.678 | 0.731 |
| 10 | 0.690 | 0.383 | 0.729 | 0.657 |
| 11 | 0.643 | 0.284 | 0.627 | 0.657 |
| 12 | 0.730 | 0.467 | 0.847 | 0.627 |
| 13 | 0.643 | 0.279 | 0.576 | 0.701 |
| 14 | 0.683 | 0.353 | 0.542 | 0.806 |
| 15 | 0.675 | 0.351 | 0.712 | 0.642 |
| 16 | 0.603 | 0.198 | 0.525 | 0.672 |
| 17 | 0.794 | 0.589 | 0.847 | 0.746 |
| 18 | 0.611 | 0.223 | 0.627 | 0.597 |
| 19 | 0.627 | 0.246 | 0.542 | 0.701 |
| 20 | 0.778 | 0.551 | 0.712 | 0.836 |
| 21 | 0.675 | 0.358 | 0.797 | 0.567 |
| 22 | 0.683 | 0.365 | 0.695 | 0.672 |
| 23 | 0.754 | 0.500 | 0.644 | 0.851 |
| 24 | 0.738 | 0.475 | 0.729 | 0.746 |
| 25 | 0.730 | 0.460 | 0.746 | 0.716 |
| 26 | 0.667 | 0.335 | 0.695 | 0.642 |
| 27 | 0.667 | 0.333 | 0.678 | 0.657 |
| 28 | 0.706 | 0.417 | 0.780 | 0.642 |
| 29 | 0.754 | 0.508 | 0.780 | 0.731 |
| 30 | 0.730 | 0.462 | 0.780 | 0.687 |
| **平均值** | **0.687** | **0.373** | **0.690** | **0.684** |
2. **分类方案2:**
| 试验次数 | 整体分类精度OA | **kappa系数** | 第一类类别分类精度AA | 第二类类别分类精度AA |
| :--------: | :------------: | :-----------: | :------------------: | :------------------: |
| 1 | 0.627 | 0.252 | 0.610 | 0.642 |
| 2 | 0.603 | 0.205 | 0.593 | 0.612 |
| 3 | 0.754 | 0.505 | 0.729 | 0.776 |
| 4 | 0.643 | 0.278 | 0.559 | 0.716 |
| 5 | 0.548 | 0.087 | 0.475 | 0.612 |
| 6 | 0.683 | 0.361 | 0.644 | 0.716 |
| 7 | 0.683 | 0.361 | 0.644 | 0.716 |
| 8 | 0.690 | 0.377 | 0.644 | 0.731 |
| 9 | 0.603 | 0.200 | 0.542 | 0.657 |
| 10 | 0.690 | 0.379 | 0.678 | 0.701 |
| 11 | 0.683 | 0.361 | 0.644 | 0.716 |
| 12 | 0.508 | 0.014 | 0.492 | 0.522 |
| 13 | 0.683 | 0.361 | 0.644 | 0.716 |
| 14 | 0.595 | 0.186 | 0.559 | 0.627 |
| 15 | 0.556 | 0.108 | 0.525 | 0.582 |
| 16 | 0.627 | 0.256 | 0.661 | 0.597 |
| 17 | 0.587 | 0.170 | 0.542 | 0.627 |
| 18 | 0.683 | 0.363 | 0.661 | 0.701 |
| 19 | 0.690 | 0.379 | 0.678 | 0.701 |
| 20 | 0.563 | 0.112 | 0.424 | 0.687 |
| 21 | 0.746 | 0.484 | 0.627 | 0.851 |
| 22 | 0.571 | 0.138 | 0.525 | 0.612 |
| 23 | 0.651 | 0.297 | 0.610 | 0.687 |
| 24 | 0.595 | 0.190 | 0.593 | 0.597 |
| 25 | 0.675 | 0.341 | 0.576 | 0.761 |
| 26 | 0.603 | 0.198 | 0.525 | 0.672 |
| 27 | 0.635 | 0.261 | 0.542 | 0.716 |
| 28 | 0.587 | 0.173 | 0.576 | 0.597 |
| 29 | 0.667 | 0.331 | 0.644 | 0.687 |
| 30 | 0.611 | 0.214 | 0.525 | 0.687 |
| **平均值** | **0.635** | **0.365** | **0.590** | **0.674** |
#### iris数据集
1. **分类方案1:**
| 实验次数 | 整体分类精度OA | kappa系数 | 类别分类精度AA(依次为第1,2,3类) |
| :--------: | :------------: | :-------: | :---------------------------------: |
| 1 | 0.900 | 0.850 | 1.00 0.767 0.933 |
| 2 | 0.911 | 0.867 | 1.00 0.800 0.933 |
| 3 | 0.833 | 0.750 | 1.00 0.800 0.700 |
| 4 | 0.956 | 0.933 | 1.00 0.900 0.967 |
| 5 | 0.922 | 0.883 | 1.00 0.900 0.867 |
| 6 | 0.967 | 0.950 | 1.00 0.900 1.000 |
| 7 | 0.900 | 0.850 | 1.00 0.800 0.900 |
| 8 | 0.944 | 0.917 | 1.00 0.900 0.933 |
| 9 | 0.933 | 0.900 | 1.00 0.967 0.833 |
| 10 | 0.956 | 0.933 | 1.00 0.933 0.933 |
| 11 | 0.900 | 0.850 | 1.00 0.833 0.867 |
| 12 | 0.822 | 0.733 | 1.00 0.667 0.800 |
| 13 | 0.833 | 0.75 | 1.00 0.800 0.700 |
| 14 | 0.967 | 0.950 | 1.00 0.933 0.967 |
| 15 | 0.878 | 0.817 | 1.00 0.633 1.000 |
| 16 | 0.922 | 0.883 | 1.00 0.933 0.833 |
| 17 | 0.644 | 0.467 | 1.00 0.433 0.500 |
| 18 | 0.900 | 0.850 | 1.00 0.833 0.867 |
| 19 | 0.900 | 0.850 | 1.00 0.867 0.833 |
| 20 | 0.889 | 0.833 | 1.00 0.867 0.800 |
| 21 | 0.900 | 0.850 | 1.00 0.900 0.800 |
| 22 | 0.900 | 0.850 | 1.00 0.833 0.867 |
| 23 | 0.911 | 0.867 | 1.00 0.967 0.767 |
| 24 | 0.944 | 0.917 | 1.00 0.833 1.000 |
| 25 | 0.944 | 0.917 | 1.00 0.967 0.867 |
| 26 | 0.922 | 0.883 | 0.97 0.867 0.933 |
| 27 | 0.956 | 0.933 | 1.00 0.900 0.967 |
| 28 | 0.922 | 0.883 | 1.00 0.900 0.867 |
| 29 | 0.956 | 0.933 | 1.00 0.933 0.933 |
| 30 | 0.878 | 0.817 | 1.00 0.767 0.867 |
| **平均值** | **0.904** | **0.856** | **0.999 0.844 0.868** |
2. **分类方案二**:
| 试验次数 | 整体分类精度OA | kappa系数 | 类别分类精度AA(依次为第1,2,3类) |
| :--------: | :------------: | :-------: | :---------------------------------: |
| 1 | 0.922 | 0.883 | 1.00 0.900 0.867 |
| 2 | 0.922 | 0.883 | 1.00 0.933 0.833 |
| 3 | 0.889 | 0.833 | 1.00 0.900 0.767 |
| 4 | 0.933 | 0.9 | 1.00 0.900 0.900 |
| 5 | 0.911 | 0.867 | 1.00 0.933 0.800 |
| 6 | 0.922 | 0.883 | 1.00 0.933 0.833 |
| 7 | 0.944 | 0.917 | 1.00 0.933 0.900 |
| 8 | 0.9 | 0.85 | 1.00 0.867 0.833 |
| 9 | 0.9 | 0.85 | 1.00 0.867 0.833 |
| 10 | 0.889 | 0.833 | 1.00 0.900 0.767 |
| 11 | 0.933 | 0.9 | 1.00 0.967 0.833 |
| 12 | 0.889 | 0.833 | 1.00 0.833 0.833 |
| 13 | 0.889 | 0.833 | 1.00 0.900 0.767 |
| 14 | 0.922 | 0.883 | 1.00 0.900 0.867 |
| 15 | 0.922 | 0.883 | 1.00 0.867 0.900 |
| 16 | 0.911 | 0.867 | 1.00 0.900 0.833 |
| 17 | 0.911 | 0.867 | 1.00 0.867 0.867 |
| 18 | 0.867 | 0.8 | 1.00 0.867 0.733 |
| 19 | 0.944 | 0.917 | 1.00 0.967 0.867 |
| 20 | 0.9 | 0.85 | 1.00 0.833 0.867 |
| 21 | 0.956 | 0.933 | 1.00 0.933 0.933 |
| 22 | 0.889 | 0.833 | 1.00 0.933 0.733 |
| 23 | 0.922 | 0.883 | 1.00 0.933 0.833 |
| 24 | 0.944 | 0.917 | 1.00 0.900 0.933 |
| 25 | 0.9 | 0.85 | 1.00 0.967 0.733 |
| 26 | 0.867 | 0.8 | 1.00 0.867 0.733 |
| 27 | 0.889 | 0.833 | 1.00 0.833 0.833 |
| 28 | 0.911 | 0.867 | 1.00 0.900 0.833 |
| 29 | 0.944 | 0.917 | 1.00 0.967 0.867 |
| 30 | 0.867 | 0.8 | 1.00 0.800 0.800 |
| **平均值** | **0.910** | **0.886** | **1.00 0.900 0.831** |
### 结果分析
1. sonar
从结果可以看出,sonar数据集的分类精度并不理想,分类方案一只有68.7%,分类方案二为63.5%,kappa系数也只有0.373、0.365,这说明分类效果较为一般,个人认为分类效果一般的原因如下:
sonar数据集的维度较高,足足有60维,而我们直接将其降到了较低的维度,降维的过程中避免不了有效信息的损失,有可能是因为有效信息损失过多,导致分类效果不理想。
可行的改进方法是降成不算太低的维度进行分类。
2. iris数据集
从结果可以看出,三分类的准确率方案一达到了90.4%,方案二为91.0%,kappa系数达到了0.856、0.886,说明分类效果很好,与实际情况几乎完全一致。
类别分类精度中第一类的精度最高,二三类稍低一点,可以看出:第一类鸢尾花在四个特征上与另外两类有较为明显的差别,很容易跟另外两类区分开来;而第二三类可能是在四个特征上的差别没有特别明显,所以分类精度会有所下降。
### 代码展示
#### 鸢尾花数据集分类(数据来源于sklearn内部封装的数据集)
1. **分类方案一:**
```python
# -*- coding: utf-8 -*-
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np
from matplotlib import pyplot as plt
import random
# 计算并返回均值向量
def junzhi(iris):
a = np.zeros([4, 1])
a[0] = np.mean(iris[:, 0])
a[1] = np.mean(iris[:, 1])
a[2] = np.mean(iris[:, 2])
a[3] = np.mean(iris[:, 3])
return a
# 计算类内离散度矩阵S_i
def S_i(iris):
a = junzhi(iris)
b = np.zeros([iris.shape[1], iris.shape[1]])
for i in range(iris.shape[0]):
b = b + np.matmul((iris[i, :].T - a), (iris[i, :].T - a).T)
return b
# 计算类间离散度矩阵S_w
def S_w(iris1, iris2):
b_1 = S_i(iris1)
b_2 = S_i(iris2)
c = b_1 + b_2
return c
# 划分训练集、测试集的函数
def train_test(iris, target, num):
train_iris, test_iris, train_target, test_target =\
train_test_split(iris, target, test_size=0.6, random_state=num, shuffle=True)
return {'train_iris': train_iris, 'test_iris': test_iris, 'train_target': train_target, 'test_target': test_target}
# 计算出最优的投影方向并计算出决策点
def best_w(iris1, iris2, target1, target2, num):
train_iris1 = train_test(iris1, target1, num)['train_iris']
train_iris2 = train_test(iris2, target2, num)['train_iris']
s_0 = S_w(train_iris1, train_iris2)
best_w = np.matmul(np.linalg.inv(s_0), junzhi(train_iris1) - junzhi(train_iris2))
y_0 = 0.5*np.mean(np.matmul(train_iris1, best_w)) + 0.5*np.mean(np.matmul(train_iris2, best_w))
# print(best_w)
return best_w, y_0
# 对测试样本进行分类并计算相关评价指标
def classify(iris1,iris2,iris3,target1,target2,target3,num):
# print(num)
## 训练集得到的最佳方向和决策点
w_best12,y0_12=best_w(iris1, iris2, target1, target2, num)
w_best13,y0_13=best_w(iris1, iris3, target1, target3, num)
w_best23,y0_23=best_w(iris2, iris3, target2, target3, num)
## 测试集
test1=train_test(iris1,target1,num)['test_iris']
test2=train_test(iris2,target2,num)['test_iris']
test3=train_test(iris3,target3,num)['test_iris']
test=np.vstack((test1,test2,test3))
## 当前测试集对应的标签
test_target1=train_test(iris1,target1,num)['test_target']
test_target2=train_test(iris2,target2,num)['test_target']
test_target3=train_test(iris3,target3,num)['test_target']
test_target=np.hstack((test_target1,test_target2,test_target3))
# print(test_target)
## 存放预测得到的标签
predict_target=np.zeros_like(test_target)
## 先通过第一二类决策函数
y=np.matmul(test,w_best12)
for i in range(len(test)):
if y[i]>y0_12 or y[i]==y0_12:
predict_target[i]=0
else:
predict_target[i]=1
## 再通过第一三类决策函数
y=np.matmul(test,w_best13)
for i in range(len(test)):
if y[i]>y0_13 or y[i]==y0_13:
predict_target[i]=0
else:
predict_target[i]=2
## 剩余的通过第二三类决策函数
y=np.matmul(test,w_best23)
for i in range(len(test)):
if predict_target[i]!=0:
if y[i]>y0_23 or y[i]==y0_23:
predict_target[i]=1
else:
predict_target[i]=2
# print(predict_target)
## 计算OA、AA、kappa系数
### 记录三类样本分类正确的数量
num_1=0
num_2=0
num_3=0
### 记录三类样本实际分类的数量
real_num_1=0
real_num_2=0
real_num_3=0
for i in range(len(test_target)):
## 统计分类正确的数量
if iy0_12 or y[i]==y0_12:
predict_target[i]=0
else:
predict_target[i]=1
# print(predict_target)
## 计算OA、AA、kappa系数
### 记录三类样本分类正确的数量
num_1=0
num_2=0
### 记录三类样本实际分类的数量
real_num_1=0
real_num_2=0
for i in range(len(test_target)):
## 统计分类正确的数量
if i