从数学到编程,从零教你Python编程实现线性判别分析LDA

从数学到编程,从零教你Python编程实现线性判别分析LDA


代码见:https://github.com/KevinTungs/LDA-python-.git

什么是线性判别分析

投影后类内方差最小,类间方差最大

线性判别分析(Linear Discriminant Analysis, 以下简称LDA),是一种监督学习的降维技术,LDA的思想可以用一句话概括,就是“投影后类内方差最小,类间方差最大”

方差可以理解为聚集的程度,方差越小,投影越靠拢

如下图的例子:
在这里插入图片描述

从直观上可以看出,右图要比左图的投影效果好,因为右图的黑色数据和蓝色数据各个较为集中,且类别之间的距离明显。左图则在边界处数据混杂。以上就是LDA的主要思想了

阈值

我们找到这样一个投影后,再在这个投影上找到一个阈值,即分为两类概率相等的地方。在这个阈值的两侧就分类为这不同的两类
在这里插入图片描述

参考资料:

https://www.bilibili.com/video/BV175411W7hv

https://www.cnblogs.com/pinard/p/6244265.html

数学基础

共轭转置矩阵与Hermitan矩阵

共轭转置矩阵 A H \bm{A}^H AH是在 A ⊺ \bm{A}^\intercal A的基础上将每一个元素取共轭,而Hermitan矩阵就是 A H = A \bm{A}^H=\bm{A} AH=A的矩阵

瑞利商(Rayleigh quotient)

定义:

R ( A , x ) = x H A x x H x R(\bm{A},\bm{x})=\frac{\bm{x}^H\bm{A}\bm{x}}{\bm{x}^H\bm{x}} R(A,x)=xHxxHAx

其中, x \bm{x} x为非零向量, A \bm{A} A为Hermitan矩阵

性质:

  1. 它可以提供方阵 A \bm{A} A的最大和最小特征值的一个界

它的最大值等于矩阵 A \bm{A} A最大的特征值,而最小值等于矩阵 A \bm{A} A的最小的特征值,即满足:

λ m i n < R ( A , x ) < λ m a x \lambda_{min}<R(\bm{A},\bm{x})<\lambda_{max} λmin<R(A,x)<λmax

当向量 x \bm{x} x是标准正交基时,即 x H x = 1 \bm{x}^H\bm{x}=1 xHx=1,瑞利商退化为 R ( x , x ) = x H A x R(\bm{x},\bm{x})={\bm{x}^H}\bm{A}\bm{x} R(x,x)=xHAx

瑞利商迭代法是一种寻找矩阵特征值的有效方法

  1. 如果 x \bm{x} x A \bm{A} A的一个特征向量,那么 R ( A , x ) R(\bm{A},\bm{x}) R(A,x)正好是对应的特征值

广义瑞利商(genralized Rayleigh quotient)

定义:

R ( A , B , x ) = x H A x x H B x R(\bm{A},\bm{B},\bm{x})=\frac{{\bm{x}^H}\bm{A}\bm{x}}{{\bm{x}^H}\bm{B}\bm{x}} R(A,B,x)=xHBxxHAx

其中, x \bm{x} x为非零向量, A , B \bm{A},\bm{B} A,B为Hermitan矩阵, B \bm{B} B为正定矩阵

性质:

它的最大值等于矩阵 B − 1 A \bm{B}^{-1}\bm{A} B1A最大的特征值,而最小值等于矩阵 B − 1 A \bm{B}^{-1}\bm{A} B1A的最小的特征值

此处,设 x = B − 1 2 x ′ \bm{x}=\bm{B}^{-\frac{1}{2}}\bm{x}' x=B21x,将广义瑞利商变换为瑞利商,再利用瑞利商的性质可以得到

协方差与协方差矩阵

协方差

定义:

c o v ( a , b ) = 1 m − 1 ∑ i = 1 m ( a i − μ a ) ( b i − μ b ) cov(a,b)=\frac{1}{m-1}\sum_{i=1}^{m}(a_i-\mu_a)(b_i-\mu_b) cov(a,b)=m11i=1m(aiμa)(biμb)

其中, m m m是样本数, a a a b b b是两个特征, μ a \mu_a μa μ b \mu_b μb是两个特征的平均值

  • 分母是m-1的情况下,估计值是总体方差的无偏估计
  • 分母是m的情况下,值是最大似然估计
  • 分母是m+1的情况下,值是最小MSE(Mean Squared Error) 的估计

此处不展开
在这里插入图片描述

协方差矩阵

定义:

Σ j = ( x − μ j ) ( x − μ j ) ⊺ \bf{\Sigma}_j=(\bm{x}-\bm{\mu}_j)(\bm{x}-\bm{\mu}_j)^\intercal Σj=(xμj)(xμj)

x \bm{x} x μ j \bm{\mu}_j μj都为 n n n维列向量

Σ j \bf{\Sigma}_j Σj n × n n\times{n} n×n矩阵

在这里插入图片描述

对角线上是方差,其他元素是协方差

参考资料:

https://www.bilibili.com/video/BV1D84y1m7rj/

拉格朗日乘子法

一种寻找多元函数在一组约束下的极值的方法,通过引入拉格朗日乘子,将有 d d d个变量与 k k k个约束条件的最优化问题转换为具有 d + k d+k d+k个变量的无约束优化问题求解

有一个等式约束条件的最优化问题

通常,一个有 d d d个变量与一个等式约束条件的最优化问题是这样表述的:

假定 x \bm{x} x d d d维向量,需要找到 x ∗ \bm{x}^* x使得目标函数 f ( x ) f(\bm{x}) f(x)最小,并满足一个等式约束 g ( x ) = 0 g(\bm{x})=0 g(x)=0

这个问题的几何意义是在方程 g ( x ) = 0 g(\bm{x})=0 g(x)=0确定的 d − 1 d-1 d1维曲面上寻找到使得 f ( x ) f(\bm{x}) f(x)最小的点

一个等式约束降低一个维度

由此可以得出下面两个结论:

  1. 对于约束曲面上的任意点 x \bm{x} x,该点的梯度 ∇ g ( x ) \nabla g(\bm{x}) g(x)正交与约束曲面
  2. 在最优点 x ∗ \bm{x}^* x,目标函数在该点的梯度 ∇ f ( x ) \nabla f(\bm{x}) f(x)正交于约束曲面

约束最优化问题转换为无约束优化问题

所以在最优点 x ∗ \bm{x}^* x ∇ g ( x ) \nabla g(\bm{x}) g(x) ∇ f ( x ) \nabla f(\bm{x}) f(x)一定方向相同或相反,也就是存在 λ ≠ 0 \lambda \neq 0 λ=0,使得:

∇ f ( x ) + λ ∇ g ( x ) = 0 \nabla f(\bm{x})+\lambda \nabla g(\bm{x}) =0 f(x)+λg(x)=0

λ \lambda λ称为拉格朗日乘子,我们定义拉格朗日函数:

L ( x , λ ) = f ( x ) + λ g ( x ) L(\bm{x},\lambda)=f(\bm{x})+\lambda g(\bm{x}) L(x,λ)=f(x)+λg(x)

对于拉格朗日函数,有:

{ ∇ x   L ( x , λ ) = ∇ f ( x ) + λ ∇ g ( x ) = 0 ∇ λ   L ( x , λ ) = g ( x ) = 0 \begin{cases} \nabla_x \ L(\bm{x},\lambda) =\nabla f(\bm{x})+\lambda\nabla g(\bm{x}) =0 \\ \nabla_\lambda\ L(\bm{x},\lambda)=g(\bm{x})=0 \end{cases} {x L(x,λ)=f(x)+λg(x)=0λ L(x,λ)=g(x)=0

式子一为前面推导的 ∇ g ( x ) \nabla g(\bm{x}) g(x) ∇ f ( x ) \nabla f(\bm{x}) f(x)一定方向相同或相反

式子二为约束条件

最优化问题就转换为了为对拉格朗日函数 L ( x , λ ) L(\bm{x},\lambda) L(x,λ)的无约束优化问题

矩阵求导

w ⊺ A w \bm{w}^\intercal A\bm{w} wAw w \bm{w} w求偏导,得到的结果是 ( A + A ⊺ ) w (A+A^\intercal)\bm{w} (A+A)w

二类LDA原理

二类指的是样本可以被分为两类,而样本的特征都为 n n n维向量

相关定义

假设我们的数据集

D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( ( x m , y m ) ) } D=\{(\bm{x}_1,y_1),(\bm{x}_2,y_2),...,((\bm{x}_m,y_m))\} D={(x1,y1),(x2,y2),...,((xm,ym))}

其中任意样本 x i \bm{x}_i xi n n n维向量, y i ∈ { 0 , 1 } y_i\in\{0,1\} yi{0,1}

我们定义:

  1. j j j类样本的个数为: N j ( j = 0 , 1 ) N_j(j=0,1) Nj(j=0,1)
  2. j j j类样本的集合为: X j ( j = 0 , 1 ) X_j(j=0,1) Xj(j=0,1)
  3. j j j类样本的均值向量为:

μ j ( j = 0 , 1 ) = 1 N j ∑ x ∈ X j x ( j = 0 , 1 ) \bm{\mu}_j(j=0,1)=\frac{1}{N_j}\sum_{\bm{x}{\in}X_j}\bm{x}(j=0,1) μj(j=0,1)=Nj1xXjx(j=0,1)

μ j ( j = 0 , 1 ) \bm{\mu}_j(j=0,1) μj(j=0,1) n n n维列向量

  1. j j j类样本的协方差矩阵:
    Σ j = ∑ x ∈ X j ( x − μ j ) ( x − μ j ) ⊺ N j − 1 ( j = 0 , 1 ) \bm{\Sigma}_j=\frac{\sum_{{\bm{x}\in}X_j}(\bm{x}-\bm{\mu}_j)(\bm{x}-\bm{\mu}_j)^\intercal}{N_j-1}(j=0,1) Σj=Nj1xXj(xμj)(xμj)(j=0,1)

Σ j \bm{\Sigma}_j Σj n × n n{\times}n n×n矩阵

投影

相关数学原理

投影计算

假设我们的投影直线是向量 w \bm{w} w,则对任意一个样本 x i \bm{x}_i xi,它在直线 w \bm{w} w的投影为 w ⊺ x i \bm{w}^{\intercal}\bm{x}_i wxi

点积, w ⊺ x i = ∣ w ∣ ∣ x i ∣ c o s ( θ ) \bm{w}^{\intercal}\bm{x}_i={\lvert}\bm{w}{\rvert}{\lvert}\bm{x}_i{\rvert}cos(\theta) wxi=wxicos(θ)

L-P范数

范数(Norm),是具有“长度”概念的函数,而L-P范数是其中一种,它是这么定义的:

L p = ∥ x ∥ p = ( ∑ i = 1 n x i p ) 1 p L_p=\lVert{x}\rVert_p=(\sum_{i=1}^n{x_i^p})^\frac{1}{p} Lp=xp=(i=1nxip)p1

性质:

  1. 正无穷范数等价于 m a x ( x i ) max(x_i) max(xi)
  2. 负无穷范数等价于 m i n ( x i ) min(x_i) min(xi)

二类LDA原理

类间方差最大

由于是两类数据,因此我们只需要将数据投影到一条直线上即可。

对于我们的两个类别的中心点 μ 0 , μ 1 \bm{\mu}_0,\bm{\mu}_1 μ0,μ1,在直线 w \bm{w} w的投影为 w ⊺ μ 0 \bm{w}^{\intercal}\bm{\mu}_0 wμ0 w ⊺ μ 1 \bm{w}^{\intercal}\bm{\mu}_1 wμ1

LDA需要让不同类别的数据的类别中心之间的距离尽可能的大

也就是我们要最大化:

∥ w ⊺ μ 0 − w ⊺ μ 1 ∥ 2 2 {\lVert}\bm{w}^\intercal\bm{\mu}_0−\bm{w}^\intercal\bm{\mu}_1{\rVert}^2_2 wμ0wμ122

L2范数再求平方

类内方差最小

同时我们希望同一种类别数据的投影点尽可能的接近,也就是令

∑ x ∈ X j ∥ ( w ⊺ x − w ⊺ μ j ) ∥ 2 2 {\sum_{{\bm{x}\in}X_j} \lVert{}(\bm{w}^{\intercal}\bm{x}-\bm{w}^\intercal\bm{\mu}_j)} \rVert_2^2 xXj(wxwμj)22

尽可能的小

w ⊺ x ( x ∈ X j ) \bm{w}^{\intercal}\bm{x}(\bm{x}\in{X_j}) wx(xXj)是单个样本在 w \bm{w} w上的投影

w ⊺ μ 0 \bm{w}^\intercal\mu_0 wμ0是样本均值在 w \bm{w} w上的投影

∑ x ∈ X j ∥ ( w ⊺ x − w ⊺ μ j ) ∥ 2 2 = ∑ x ∈ X j ( w ⊺ ( x − μ j ) ) 2 = ∑ x ∈ X j ( w ⊺ ( x − μ j ) ) ( w ⊺ ( x − μ j ) ) ⊺ = ∑ x ∈ X j ( w ⊺ ( x − μ j ) ) ( w ⊺ ( x − μ j ) ) ⊺ = ∑ x ∈ X j ( w ⊺ ( x − μ j ) ( x − μ j ) ⊺ w ) = ∑ x ∈ X j w ⊺ Σ j w ( j = 0 , 1 ) \begin{equation*} \begin{split} &{\sum_{{\bm{x}\in}X_j}\lVert{}(\bm{w}^{\intercal}\bm{x}-\bm{w}^\intercal\bm{\mu}_j)}\rVert_2^2\\ =&{\sum_{{\bm{x}\in}X_j}}(\bm{w}^{\intercal}(\bm{x}-\bm{\mu}_j))^2\\ =&{\sum_{{\bm{x}\in}X_j}}(\bm{w}^{\intercal}(\bm{x}-\bm{\mu}_j))(\bm{w}^{\intercal}(\bm{x}-\bm{\mu}_j))^{\intercal} \\ =&{\sum_{{\bm{x}\in}X_j}}(\bm{w}^{\intercal}(\bm{x}-\bm{\mu}_j))(\bm{w}^{\intercal}(\bm{x}-\bm{\mu}_j))^{\intercal}\\ =&{\sum_{{\bm{x}\in}X_j}}(\bm{w}^{\intercal}(\bm{x}-\bm{\mu}_j)(\bm{x}-\bm{\mu}_j)^{\intercal}\bm{w})\\ =&{\sum_{{\bm{x}\in}X_j}}\bm{w}^{\intercal}\bm{\Sigma}_j\bm{w}(j=0,1) \end{split} \end{equation*} =====xXj(wxwμj)22xXj(w(xμj))2xXj(w(xμj))(w(xμj))xXj(w(xμj))(w(xμj))xXj(w(xμj)(xμj)w)xXjwΣjw(j=0,1)

因为 w ⊺ ( x − μ j ) \bm{w}^{\intercal}(\bm{x}-\bm{\mu}_j) w(xμj)是常量,所以可以整体取转置,不影响结果,便于计算

也就是要同类样本投影点的协方差 w ⊺ Σ 0 w \bm{w}^\intercal{\bm{\Sigma}}_0\bm{w} wΣ0w w ⊺ Σ 1 w \bm{w}^\intercal{\bm{\Sigma}}_1\bm{w} wΣ1w尽可能的小

即最小化:

w ⊺ Σ 0 w + w ⊺ Σ 1 w \bm{w}^\intercal{\bm{\Sigma}}_0\bm{w} +\bm{w}^\intercal{\bm{\Sigma}}_1\bm{w} wΣ0w+wΣ1w

优化目标,类内散度矩阵与类间散度矩阵

综上所述,我们可以将优化目标定义为:

arg ⁡ max ⁡ ⏟ w J ( w ) = ∥ w ⊺ μ 0 − w ⊺ μ 1 ∥ 2 2 w ⊺ Σ 0 w + w ⊺ Σ 1 w = w ⊺ ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) ⊺ w w ⊺ ( Σ 0 + Σ 1 ) w \begin{split} \underbrace{\arg\max}_{\bm{w}}J(\bm{w}) &=\frac{{\lVert}\bm{w}^\intercal\bm{\mu}_0−\bm{w}^\intercal\bm{\mu}_1{\rVert}^2_2} {\bm{w}^\intercal\bm{\Sigma}_0\bm{w}+\bm{w}^\intercal\bm{\Sigma}_1\bm{w}}\\ &=\frac{\bm{w}^\intercal(\bm{\mu}_0−\bm{\mu}_1)(\bm{\mu}_0−\bm{\mu}_1)^{\intercal}\bm{w}}{\bm{w}^\intercal(\bm{\Sigma}_0+\bm{\Sigma}_1)\bm{w}} \end{split} w argmaxJ(w)=wΣ0w+wΣ1wwμ0wμ122=w(Σ0+Σ1)ww(μ0μ1)(μ0μ1)w

arg ⁡ max ⁡ ⏟ w J ( w ) \underbrace{\arg\max}_{\bm{w}}J(\bm{w}) w argmaxJ(w)表示令函数 J ( w ) J(\bm{w}) J(w)最大的时候的 w \bm{w} w

这个表达式的形式就和广义瑞利商很相近了,我们可以定义:

  1. 类内散度矩阵: S w = Σ 0 + Σ 1 \bm{S}_w=\bf{\Sigma}_0+\bf{\Sigma}_1 Sw=Σ0+Σ1
  2. 类间散度矩阵: S b = ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) ⊺ \bm{S}_b=(\bm{\mu}_0−\bm{\mu}_1)(\bm{\mu}_0−\bm{\mu}_1)^{\intercal} Sb=(μ0μ1)(μ0μ1)

S w \bm{S}_w Sw S b \bm{S}_b Sb都是对称矩阵

此时优化目标可以写为:

arg ⁡ max ⁡ ⏟ w J ( w ) = w ⊺ S b w w ⊺ S w w = R ( S b , S w , w ) \begin{split} \underbrace{\arg\max}_{\bm{w}}J(\bm{w}) &=\frac{\bm{w}^\intercal\bm{S}_b\bm{w}} {\bm{w}^\intercal{\bm{S}_w}\bm{w}}\\ &=R(\bm{S}_b,\bm{S}_w,\bm{w}) \end{split} w argmaxJ(w)=wSwwwSbw=R(Sb,Sw,w)

利用广义瑞利商的最大值等于矩阵 B − 1 A \bm{B}^{-1}\bm{A} B1A最大的特征值,而最小值等于矩阵 B − 1 A \bm{B}^{-1}\bm{A} B1A的最小的特征值的性质

R ( A , B , x ) = x H A x x H B x R(\bm{A},\bm{B},\bm{x})=\frac{{\bm{x}^H}\bm{A}\bm{x}}{{\bm{x}^H}\bm{B}\bm{x}} R(A,B,x)=xHBxxHAx

J ( w ) J(\bm{w}) J(w)的最大值为矩阵 S w − 1 S b \bm{S}_w^{-1}\bm{S}_b Sw1Sb的最大特征值,对应的 w \bm{w} w就是该特征值对应的特征向量

使用拉格朗日乘子法确定投影直线

arg ⁡ max ⁡ ⏟ w J ( w ) = w ⊺ S b w w ⊺ S w w = R ( S b , S w , w ) \begin{split} \underbrace{\arg\max}_{\bm{w}}J(\bm{w}) &=\frac{\bm{w}^\intercal{\bm{S}_b}\bm{w}}{\bm{w}^\intercal{\bm{S}_w}\bm{w}}\\ &=R(\bm{S}_b,\bm{S}_w,\bm{w}) \end{split} w argmaxJ(w)=wSwwwSbw=R(Sb,Sw,w)

我们可以发现,式子中分子分母都是关于 w \bm{w} w的二次项,所以 w ∗ \bm{w}^* w a w ∗ a\bm{w}^* aw都是解。也就是说,解与 w \bm{w} w的长度无关,只与其方向有关

所以,我们可以假设 w ⊺ S w w = 1 \bm{w}^\intercal{\bm{S}_w}\bm{w}=1 wSww=1,将目标转化为:

arg ⁡ min ⁡ ⏟ w − w ⊺ S b w s . t . w ⊺ S w w = 1 \begin{split} {\underbrace{\arg\min}_{\bm{w}}} &\quad{-\bm{w}^\intercal{\bm{S}_b}\bm{w}}\\ s.t. &\quad\bm{w}^\intercal{\bm{S}_w}\bm{w}=1 \end{split} w argmins.t.wSbwwSww=1

由拉格朗日乘子法,可设拉格朗日函数为:

L ( w , λ ) = − w ⊺ S b w + λ ( w ⊺ S w w − 1 ) ∇ w L ( w , λ ) = − 2 S b w + 2 λ S w w \begin{split} L(\bm{w},\lambda) &=-\bm{w}^\intercal \bm{S}_b \bm{w} +\lambda(\bm{w}^\intercal{\bm{S}_w}\bm{w}-1)\\ \nabla_wL(\bm{w},\lambda) &=-2\bm{S}_b\bm{w}+2\lambda\bm{S}_w\bm{w} \end{split} L(w,λ)wL(w,λ)=wSbw+λ(wSww1)=2Sbw+2λSww

S w \bm{S}_w Sw S b \bm{S}_b Sb都是对称矩阵

又:

∇ w L ( w , λ ) = 0 − 2 S b w + 2 λ S w w = 0 S b w = λ S w w ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) ⊺ w = λ S w w \begin{split} \nabla_wL(\bm{w},\lambda)& =0\\ -2\bm{S}_b\bm{w}+2\lambda\bm{S}_w\bm{w}& =0\\ \bm{S}_b\bm{w}& =\lambda\bm{S}_w\bm{w}\\ (\bm{\mu}_0−\bm{\mu}_1)(\bm{\mu}_0−\bm{\mu}_1)^{\intercal}\bm{w}& =\lambda\bm{S}_w\bm{w} \end{split} wL(w,λ)2Sbw+2λSwwSbw(μ0μ1)(μ0μ1)w=0=0=λSww=λSww

我们令 ( μ 0 − μ 1 ) ⊺ w = γ (\bm{\mu}_0−\bm{\mu}_1)^{\intercal}\bm{w}=\gamma (μ0μ1)w=γ,得到:

γ ( μ 0 − μ 1 ) = λ S w w w = γ λ S w − 1 ( μ 0 − μ 1 ) \begin{split} \gamma(\bm{\mu}_0−\bm{\mu}_1)& =\lambda\bm{S}_w\bm{w}\\ \bm{w}& =\frac{\gamma}{\lambda}\bm{S}_w^{-1}(\bm{\mu}_0−\bm{\mu}_1) \end{split} γ(μ0μ1)w=λSww=λγSw1(μ0μ1)

λ \lambda λ γ \gamma γ是常量

因为我们不关心 w \bm{w} w的大小,只关心方向,所以我们可以求:

w ′ = λ γ w = S w − 1 ( μ 0 − μ 1 ) \bm{w}' =\frac{\lambda}{\gamma}\bm{w} =\bm{S}_w^{-1}(\bm{\mu}_0−\bm{\mu}_1) w=γλw=Sw1(μ0μ1)

其中:

S w = Σ 0 + Σ 1 = ( x − μ 0 ) ( x − μ 0 ) ⊺ + ( x − μ 1 ) ( x − μ 1 ) ⊺ \bm{S}_w =\bf{\Sigma}_0+\bf{\Sigma}_1 =(\bm{x}-\bm{\mu}_0)(\bm{x}-\bm{\mu}_0)^\intercal+(\bm{x}-\bm{\mu}_1)(\bm{x}-\bm{\mu}_1)^\intercal Sw=Σ0+Σ1=(xμ0)(xμ0)+(xμ1)(xμ1)

μ j ( j = 0 , 1 ) = 1 N j ∑ x ∈ X j x ( j = 0 , 1 ) \bm{\mu}_j(j=0,1)=\frac{1}{N_j}\sum_{\bm{x}{\in}X_j}\bm{x}(j=0,1) μj(j=0,1)=Nj1xXjx(j=0,1)

即得到了投影直线 w \bm{w} w

例题:

题目

请用Python编程实现线性判别分析LDA,并给出下面数据集上的结果及说明。如果你在作业完成过程当中借助了ChatGPT等AI工具,请写出相应的使用过程说明。

编号属性1属性2类别
10.6660.091正例
20.2430.267正例
30.2440.056正例
40.3420.098正例
50.6380.16正例
60.6560.197正例
70.3590.369正例
80.5920.041正例
90.7180.102正例
100.6970.46反例
110.7740.376反例
120.6330.263反例
130.6070.317反例
140.5550.214反例
150.4020.236反例
160.4810.149反例
170.4360.21反例
180.5570.216反例

代码

# by KevinTung
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimSun']  # 设置中文显示字体
plt.rcParams['axes.unicode_minus'] = False   # 正确显示负号

# 数据集
data = np.array([
    [0.666, 0.091, 1],
    [0.243, 0.267, 1],
    [0.244, 0.056, 1],
    [0.342, 0.098, 1],
    [0.638, 0.16, 1],
    [0.656, 0.197, 1],
    [0.359, 0.369, 1],
    [0.592, 0.041, 1],
    [0.718, 0.102, 1],
    [0.697, 0.46, 0],
    [0.774, 0.376, 0],
    [0.633, 0.263, 0],
    [0.607, 0.317, 0],
    [0.555, 0.214, 0],
    [0.402, 0.236, 0],
    [0.481, 0.149, 0],
    [0.436, 0.21, 0],
    [0.557, 0.216, 0]
])

# 分离特征和标签
X = data[:, :2]
y = data[:, 2]

# 计算正例和反例的均值向量
mu_0 = np.mean(X[y == 0], axis=0)
mu_1 = np.mean(X[y == 1], axis=0)

# 计算类内散度矩阵
S_w = np.zeros((2, 2))
for i in range(len(X)):
    if y[i] == 0:
        S_w += np.outer(X[i] - mu_0, X[i] - mu_0)
    else:
        S_w += np.outer(X[i] - mu_1, X[i] - mu_1)

# 计算最优投影方向
w_prime = np.linalg.inv(S_w).dot(mu_0 - mu_1)

# 计算LDA分割线(决策边界),决策边界垂直于投影向量w_prime,且通过两个类别均值的中点
mid_point = (mu_0 + mu_1) / 2
slope = w_prime[1] / w_prime[0]

# 计算垂直于投影向量的斜率
slope_perpendicular = -1 / slope

# 计算截距
intercept_perpendicular = mid_point[1] - slope_perpendicular * mid_point[0]

# 绘制数据点
plt.figure(figsize=(10, 6))
plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='blue', label='正例')
plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='red', label='反例')

# 绘制LDA分割线
x_values = np.linspace(0, 1, 100)  # x值
y_values = slope_perpendicular * x_values + intercept_perpendicular  # 对应的y值
plt.plot(x_values, y_values, color='green', label='LDA 分割线')

# 其他图形设置
plt.xlabel('属性1')
plt.ylabel('属性2')
plt.legend()
plt.title('数据集和LDA分割线')
plt.show()

# 输出投影向量
print(f'投影向量为:{w_prime}')
# 输出LDA分割线的方程
print(f'LDA分割线的方程为:y = {slope_perpendicular}x + {intercept_perpendicular}')

结果

投影向量为:[0.14340516 0.68106694]
LDA分割线的方程为:y = -0.21055955976278984x + 0.3246317652068213

在这里插入图片描述

代码解析

导入包

import numpy as np
import matplotlib.pyplot as plt

NumPy 是 Python 中用于科学计算的核心库之一,提供了高性能的多维数组对象以及用于数组操作的各种工具

Matplotlib 是 Python 中用于创建静态、交互式和动态可视化的二维图形库。它提供了类似于 MATLAB 的绘图接口,使得用户能够轻松地生成各种类型的图表、图形和动画

Matplotlib设置字体

plt.rcParams['font.sans-serif'] = ['Hei'] # 设置中文显示字体
plt.rcParams['axes.unicode_minus'] = False   # 正确显示负号

使用 Matplotlib 库中的 rcParams 属性,用于配置全局的绘图参数

  1. 使用黑体,解决中文显示问题
  2. 使用减号显示负号,解决显示问题
  • 在 Python 中,字典是一种无序的数据结构,用于存储键值对字典的语法是使用大括号 {} 来创建,键值对之间使用冒号 : 分隔,每个键值对之间使用逗号 , 分隔。{'font.sans-serif': ['Hei']} 是一个字典,其中 'font.sans-serif' 是键,['Hei'] 是与之对应的值
  • ['Hei']是一个列表,plt.rcParams['font.sans-serif'] 这个参数要求接受一个字体名称的列表,而不是单独的字符串。虽然我们只需要指定一个中文字体,但是Matplotlib中 font.sans-serif 这个参数的设计是允许用户指定多个备选的字体名称的,这样做的目的是为了在系统中找不到指定字体时能够自动回退到备选的字体。因此,即使只有一个字体,也需要将其放入列表中作为 font.sans-serif 的值。
  • plt.rcParams['axes.unicode_minus'] = False:这一行代码用于设置图表中显示的负号(即减号)的样式,将其设置为不显示负号。在一些情况下,默认情况下 Matplotlib 可能会显示不正确的负号,比如显示为方块或者其他字符,通过将 axes.unicode_minus 参数设置为 False,可以避免这种情况设置为 False 表示不显示负号,而如果设置为 True,则显示标准的减号

设置数据集

# 数据集
data = np.array([
    [0.666, 0.091, 1],
    [0.243, 0.267, 1],
    [0.244, 0.056, 1],
    [0.342, 0.098, 1],
    [0.638, 0.16, 1],
    [0.656, 0.197, 1],
    [0.359, 0.369, 1],
    [0.592, 0.041, 1],
    [0.718, 0.102, 1],
    [0.697, 0.46, 0],
    [0.774, 0.376, 0],
    [0.633, 0.263, 0],
    [0.607, 0.317, 0],
    [0.555, 0.214, 0],
    [0.402, 0.236, 0],
    [0.481, 0.149, 0],
    [0.436, 0.21, 0],
    [0.557, 0.216, 0]
])

分离特征和标签

# 分离特征和标签
X = data[:, :2]
y = data[:, 2]
  1. X = data[:, :2]

这行代码的作用是提取 data 数组中的前两列,这两列包含了每个数据点的属性

  • data[:, :2] 中的第一个 : 代表选择所有行
  • :2 表示选择从第一列开始到第二列(不包括索引为2的第三列)的所有列

结果 X 就是一个只包含数据集中所有数据点的属性的二维数组

  1. y = data[:, 2]

这行代码的作用是提取 data 数组中的第三列,这一列包含了每个数据点的类别标签

  • data[:, 2] 中的第一个 : 同样代表选择所有行
  • 2 表示选择第三列(因为在Python中索引是从0开始的)

结果 y 就是一个一维数组,包含了数据集中所有数据点的类别标签

计算均值向量

# 计算正例和反例的均值向量
mu_0 = np.mean(X[y == 0], axis=0)
mu_1 = np.mean(X[y == 1], axis=0)
  1. mu_0 = np.mean(X[y == 0], axis=0)

这行代码计算所有类别标签为0的样本点的特征均值

X[y == 0] 是利用布尔索引从数组 X 中选择出所有类别标签为0的样本点。

  • y == 0 生成一个布尔数组,其中 y 中每个元素等于0的位置是 True,不等于0的位置是 False
  • 当这个布尔数组用作 X 的索引时,它会选择 X 中所有对应于 True 的行
  • np.mean(..., axis=0) 计算所选样本点特征的均值,axis=0指的是沿着数组的第一个轴进行操作,即指定沿着列(垂直方向)进行计算,即分别为每个特征(列)计算均值
  1. mu_1 = np.mean(X[y == 1], axis=0)

与上一行代码类似,这行代码计算所有类别标签为1的样本点的特征均值。X[y == 1] 选择出了所有类别标签为1的样本点。

计算类内散度矩阵

# 计算类内散度矩阵
S_w = np.zeros((2, 2))
for i in range(len(X)):
    if y[i] == 0:
        S_w += np.outer(X[i] - mu_0, X[i] - mu_0)
    else:
        S_w += np.outer(X[i] - mu_1, X[i] - mu_1)

np.outer()函数计算了两个向量的外积,即将第一个向量乘以第二个向量的转置,产生一个矩阵。在这里,它被用来计算差向量乘以其转置,然后累加到类内散度矩阵中

  • 类间散度矩阵:
    S w = Σ 0 + Σ 1 = ∑ x ∈ X 0 ( x − μ 0 ) ( x − μ 0 ) ⊺ + ∑ x ∈ X 1 ( x − μ 1 ) ( x − μ 1 ) ⊺ \bm{S}_w =\bf{\Sigma}_0+\bf{\Sigma}_1 =\sum_{\bm{x}\in\bm{X}_0}(\bm{x}-\bm{\mu}_0)(\bm{x}-\bm{\mu}_0)^\intercal +\sum_{\bm{x}\in\bm{X}_1}(\bm{x}-\bm{\mu}_1)(\bm{x}-\bm{\mu}_1)^\intercal Sw=Σ0+Σ1=xX0(xμ0)(xμ0)+xX1(xμ1)(xμ1)

  • 外积(Outer Product),也称为张量积或叉积,在向量的情况下,外积用于计算两个向量的结果矩阵,结果矩阵的维度等于输入向量的维度的乘积

  • 内积(Inner Product),也称为点积或数量积,在向量的情况下,内积用于计算两个向量之间的数量关系,结果是一个标量

计算最优投影方向

# 计算最优投影方向
w_prime = np.linalg.inv(S_w).dot(mu_0 - mu_1)
  1. np.linalg.inv(S_w): 这部分使用 NumPy 中的 np.linalg.inv() 函数计算了矩阵 S_w 的逆矩阵。np.linalg.inv() 用于计算给定矩阵的逆矩阵
  2. .dot(mu_0 - mu_1): 这部分对计算得到的逆矩阵与向量 mu_0 - mu_1 进行点乘操作。mu_0 - mu_1 表示两个均值向量的差向量,点乘操作则表示矩阵与向量的乘法运算

最优投影方向: w ′ = λ γ w = S w − 1 ( μ 0 − μ 1 ) \bm{w}' =\frac{\lambda}{\gamma}\bm{w} =\bm{S}_w^{-1}(\bm{\mu}_0−\bm{\mu}_1) w=γλw=Sw1(μ0μ1)

计算LDA分割线

# 计算LDA分割线(决策边界),决策边界垂直于投影向量w_prime,且通过两个类别均值的中点
mid_point = (mu_0 + mu_1) / 2
slope = w_prime[1] / w_prime[0]

# 计算垂直于投影向量的斜率
slope_perpendicular = -1 / slope

# 计算截距
intercept_perpendicular = mid_point[1] - slope_perpendicular * mid_point[0]

相互垂直的向量斜率之积为-1

绘制数据点

# 绘制数据点
plt.figure(figsize=(10, 6))
plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='blue', label='正例')
plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='red', label='反例')
  1. plt.figure(figsize=(10, 6))

这一行创建了一个新的图形窗口,其大小为10英寸宽和6英寸高。figsize参数是一个元组,指定了窗口的宽度和高度(单位是英寸)。这为接下来的绘图提供了一个“画布”

  1. plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='blue', label='正例')

这一行绘制了所有正例的数据点。plt.scatter函数用于绘制散点图,其中第一个参数是x轴上的值,第二个参数是y轴上的值

X[y == 1][:, 0]选择了X中所有标签y为1的行的第一列(即第一个特征),用作x轴的坐标

  1. X[y == 1][:, 1]选择了相同行的第二列(即第二个特征),用作y轴的坐标

  2. color='blue'指定了点的颜色为蓝色

  3. label='正例'给这些点的集合添加了一个标签,称为“正例”,这个标签将在图例中显示

  1. plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='red', label='反例')

  2. 这一行与前一行类似,但它是为所有反例的数据点绘制散点图

  3. 通过X[y == 0][:, 0]X[y == 0][:, 1]选择了所有标签y为0的数据点,分别用作x轴和y轴的坐标。

  4. 这些点被设置为红色(color='red'),并被标记为“反例”(label='反例'

绘制LDA分割线

# 绘制LDA分割线
x_values = np.linspace(0, 1, 100)  # x值
y_values = slope * x_values + intercept_perpendicular  # 对应的y值
plt.plot(x_values, y_values, color='green', label='LDA 分割线')

其他图形设置

# 其他图形设置
plt.xlabel('属性1')
plt.ylabel('属性2')
plt.legend()
plt.title('数据集和LDA分割线')
plt.show()

plt.legend() 用于添加图例到当前图形中

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值