判别分析数学原理推导-实战(基于R语言的mlr,tidyverse;Python-sklearn)

主要内容

  • 理解线性判别分析和二次判别分析

  • 建立线性判别分类器,对葡萄酒数据集进行预测

什么是判别分析

判别分析(Discriminant analysis)是一种统计分析方法,旨在通过将一组对象(例如观察数据)分类到已知类别的组中,来发现不同组之间的差异。

判别分析有两种主要形式:线性判别分析(LDA)和二次判别分析(QDA)。LDA假设每个类别的协方差矩阵相同,并寻找最优的判别方向来最大化类别之间的距离。QDA假设每个类别的协方差矩阵都不同,并寻找最优的判别方向来最大化类别之间的距离,同时也考虑了每个类别的协方差矩阵。

线性判别分析(LDA)

当我们有一个由 n n n 个样本和 p p p 个特征组成的数据集时,LDA的目标是找到一个线性变换,将数据从 p p p 维空间映射到 k k k 维空间( k < p k<p k<p),使得在新的空间中,同一类别内的数据点尽可能相似,不同类别之间的数据点尽可能分离。

线性判别分析的数学原理

我们以二分类问题为例:假设数据集是 D = { ( x i , y i } i = 1 m , y i ∈ { 0 , 1 } D=\{(x_i,y_i\}_{i=1}^m,y_i\in\{0,1\} D={(xi,yi}i=1m,yi{0,1},设 μ i \mu_i μi为第 i i i类样本的均值向量; X i X_i Xi为第 i i i类样本的集合; Σ i \Sigma_i Σi为第 i i i类样本的协方差矩阵, i = 0 , 1 i=0,1 i=0,1.

将样本数据投影至直线 y = w T x y=w^Tx y=wTx上,则两类样本中心在直线上的投影分别为 w T μ 0 , w T μ 1 w^T\mu_0,w^T\mu_1 wTμ0,wTμ1,两类样本在直线上的协方差分别为 w T Σ 0 w , w T Σ 1 w w^T\Sigma_0w,w^T\Sigma_1w wTΣ0w,wTΣ1w.

  • 同类样本点的投影点尽量接近,也就是同类样本点投影后的协方差 w T Σ 0 w , w T Σ 1 w w^T\Sigma_0w,w^T\Sigma_1w wTΣ0w,wTΣ1w尽可能小

  • 异类样本的投影点尽可能远离,也就是不同类样本点的类中心之间的距离 ∥ w T μ 0 − w T μ 1 ∥ 2 2 \|w^T\mu_0-w^T\mu_1\|_2^2 wTμ0wTμ122尽可能大

目标函数

J ( w ) = max ⁡ w ∥ w T μ 0 − w T μ 1 ∥ 2 w T Σ 0 w + w T Σ 1 w J(w)=\max_{w} \dfrac{\|w^T\mu_0-w^T\mu_1\|^2}{w^T\Sigma_0w+w^T\Sigma_1w} J(w)=wmaxwTΣ0w+wTΣ1wwTμ0wTμ12
将上面的公式化简,得到:
J ( w ) = max ⁡ w w T ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) T w w T ( Σ 0 + Σ 1 ) w J(w)=\max_{w}\dfrac{w^T(\mu_0-\mu_1)(\mu_0-\mu_1)^Tw}{w^T(\Sigma_0+\Sigma_1)w} J(w)=wmaxwT(Σ0+Σ1)wwT(μ0μ1)(μ0μ1)Tw

我们记 S b = ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) T , S w = Σ 0 + Σ 1 S_b=(\mu_0-\mu_1)(\mu_0-\mu_1)^T,S_w=\Sigma_0+\Sigma_1 Sb=(μ0μ1)(μ0μ1)T,Sw=Σ0+Σ1,我们最终可以目标函数为 J ( w ) = max ⁡ w w T S b w w T S w w J(w)=\max_{w}\dfrac{w^TS_bw}{w^TS_ww} J(w)=wmaxwTSwwwTSbw

拉格朗日乘子法求解

由于求解的 w w w是一个方向向量,与模长无关,我们可以令 w T S w w = 1 w^TS_ww=1 wTSww=1,于是目标函数变为: min ⁡ − w T S b w , w T S w w = 1 \min -w^TS_bw , w^TS_ww=1 minwTSbw,wTSww=1

  • 写出对偶拉格朗日函数: max ⁡ λ min ⁡ w − w T S b w + λ ( w T S w w − 1 ) \max_\lambda \min_{w} -w^TS_bw+\lambda(w^TS_ww-1) λmaxwminwTSbw+λ(wTSww1)

我们令 F ( w ) = − w T S b w + λ ( w T S w w − 1 ) F(w)=-w^TS_bw+\lambda(w^TS_ww-1) F(w)=wTSbw+λ(wTSww1),欲求 min ⁡ F ( w ) \min F(w) minF(w),需要求解 ∇ w F ( w ) = − 2 S b w + 2 λ S w w = 0 \nabla_wF(w)=-2S_bw+2\lambda S_ww=0 wF(w)=2Sbw+2λSww=0,即 S b w = λ S w w S_bw=\lambda S_w w Sbw=λSww,注意 S b w = ( μ 0 − μ 1 ) ( μ 0 − μ 1 ) T w S_bw=(\mu_0-\mu_1)(\mu_0-\mu_1)^Tw Sbw=(μ0μ1)(μ0μ1)Tw中的 ( μ 0 − μ 1 ) T w (\mu_0-\mu_1)^Tw (μ0μ1)Tw是一个实数,方向恒为 μ 0 − μ 1 \mu_0-\mu_1 μ0μ1,因此我们可以不妨设 S b w = λ ( μ 0 − μ 1 ) S_bw=\lambda(\mu_0-\mu_1) Sbw=λ(μ0μ1),最终得到: λ ( μ 0 − μ 1 ) = λ S w w \lambda(\mu_0-\mu_1)=\lambda S_ww λ(μ0μ1)=λSww,求解得到:
w = S w − 1 ( μ 0 − μ 1 ) w=S_w^{-1}(\mu_0-\mu_1) w=Sw1(μ0μ1)
S w S_w Sw矩阵不可逆时,我们通常使用奇异值分解 S w = U Σ V T S_w=U\Sigma V^T Sw=UΣVT

二次判别分析(QDA)

QDA(Quadratic Discriminant Analysis)是一种有监督的机器学习算法,用于分类问题。它是 LDA(Linear Discriminant Analysis,线性判别分析)的一种扩展形式,与 LDA 类似,QDA 也是一种基于贝叶斯决策理论的分类器。与 LDA 不同的是,QDA 假设每个类别的协方差矩阵不相同,因此在分类时使用的决策边界是二次曲线。

构建线性和二次判别模型

加载和研究葡萄酒数据集

library(mlr)
library(tidyverse)

加载HDclassif程序包内置的葡萄酒数据,将其转换为tibble:

library(HDclassif)
data(wine,package = "HDclassif")
wineTib <- as_tibble(wine)

手动添加变量名称:

names(wineTib) <- c("Class","Alco","Malic","Ash","Alk","Mag","Phe","Flav","Non_flav","Proan","Col","Hue","OD","Prol")
wineTib$Class <- as.factor(wineTib$Class)

检查有无缺失值:

colSums(is.na(wineTib))

绘制数据图

wineUntidy <- gather(wineTib,"Variable","Value",-Class)

ggplot(wineUntidy,aes(Class,Value))+
  facet_wrap(~ Variable,scales = "free_y")+
  geom_boxplot()+
  theme_bw()

在这里插入图片描述

训练模型

wineTask <- makeClassifTask(data = wineTib,target = "Class")
lda <- makeLearner("classif.lda")
ldaModel <-train(lda,wineTask)

使用getLearnerModel()函数提取模型信息,并使用predict()函数获取每个样本的DF值。

ldaModeldata<- getLearnerModel(ldaModel)
ldaPreds <-predict(ldaModeldata)$x
head(ldaPreds)

可视化建模

为了可视化算法学习到的两个DF如何很好地将三个葡萄园的数据分开,可以对他们进行对比绘制。

wineTib %>%
  mutate(LD1 = ldaPreds[,1],
         LD2 = ldaPreds[,2])%>%
  ggplot(aes(LD1,LD2,col = Class))+
  geom_point()+
  stat_ellipse()+ #在每个类别的周围绘制95%的置信度椭圆
  theme_bw()

在这里插入图片描述

构建QDA模型

qda <- makeLearner("classif.qda")
qdaModel <- train(qda,task = wineTask)

交叉验证LDA和QDA模型

kFold <- makeResampleDesc(method = "RepCV",folds = 10,reps = 2,stratify = TRUE)

ldaCV <- resample(learner = lda,task = wineTask,resampling = kFold,measures = list(acc,mmce))

qdaCV <- resample(learner = qda,task = wineTask,resampling = kFold,measures = list(acc,mmce))
ldaCV$aggr
qdaCV$aggr

LDA 模型平均对约为98.6%的样本进行了正确分类,QDA模型平均对约为99.4%的样本进行了正确分类。

输出混淆矩阵:

calculateConfusionMatrix(ldaCV$pred,relative = TRUE)
calculateConfusionMatrix(qdaCV$pred,relative = TRUE)

对未知数据进行预测

newdata <- tibble(Alco=13,Malic=2,Ash=2.2,Alk=19,Mag=100,Phe=2.3,Flav=2.5,Non_flav=0.35,Proan=1.7,Col=4,Hue=1.1,OD=3,Prol=750)
lda_pre<-predict(ldaModel,newdata = newdata)$data #输出为2
qda_pre<-predict(qdaModel,newdata = newdata)$data #输出为1

将数据导出为csv方便后续使用:

#write_csv(wineTib,"葡萄酒数据集.csv")

LDA和QDA算法的优缺点

1.优点

  • 可以将高维特征空间的数据压缩到易于管理的低维空间
  • 可用于分类或者其他分类算法的预处理(降维)技术
  • QDA可以学习到类别之间弯曲的决策边界

2.缺点

  • 只能处理连续预测变量
  • 假设数据特征服从正态分布,如果数据不服从正态分布,LDA和QDA模型的表现较差
  • QDA容易过拟合

复习KNN调参练习

从LDA模型中提取判别分数,并将这些类别分数用作KNN模型的自变量,在整个过程使用交叉验证,并同时调整超参数k

# 创建任务
new<-wineTib %>%
  mutate(LD1=ldaPreds[, 1], LD2=ldaPreds[, 2]) 
newData<-new[,c(1,15,16)]
newTask <- makeClassifTask(data = newData,target = "Class")
# 创建学习器
knn <- makeLearner("classif.knn",par.vals = list("k"=5)) #初始化一个学习器,超参数定义为5
knnModel <- train(learner = knn,task = newTask)
# 调整超参数k
knnParamSpace <- makeParamSet(makeDiscreteLearnerParam("k",values = 1:10))
gridsearch <- makeTuneControlGrid() #使用网格搜索
cvForTuning <- makeResampleDesc(method = "RepCV",folds=10,reps=20)
tunedK <- tuneParams(learner = knn,task = newTask,resampling = cvForTuning,measures = list(mmce),par.set = knnParamSpace,control = gridsearch)
knnTuningData <- generateHyperParsEffectData(tunedK)
plotHyperParsEffect(knnTuningData,x="k",y="mmce.test.mean",plot.type = "line")+
  theme_bw()

将数据写入csv文件,便于Python导入:

write_csv(newData,"三分类数据集.csv")

下面使用Python中的KNN算法以及网格搜索参数调优

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split,GridSearchCV
import pandas as pd
data = pd.read_csv("三分类数据集.csv")
data_shuffle = data.sample(frac=1,random_state=42) #将数据按照行进行打乱
y= data_shuffle["Class"]
x = data_shuffle.drop("Class",axis=1,inplace=False)
X_train,X_test,y_train,y_test = train_test_split(x.values,y.values,test_size=0.2,random_state=42)
knn = KNeighborsClassifier()
knn.fit(X_train,y_train)
y_pre = knn.predict(X_test)
pre_true_df = pd.DataFrame()
pre_true_df["true"] = y_test
pre_true_df["predict"] = y_pre
pre_true_df ##这里准确率已经百分百了

虽然上面的模型在测试集已经达到百分之百了,但是我们的数据集规模太小了,我们还是要学习一下如何在Python中进行参数调优吧(网格搜索)

k_range = list(range(1, 10))
param_grid = dict(n_neighbors=k_range)
grid = GridSearchCV(knn, param_grid, cv=10, scoring='accuracy')
grid.fit(x, y)

print("Best score: {:.2f}%".format(grid.best_score_*100))
print("Best parameters: {}".format(grid.best_params_))

现在调用Python中的LDA算法和QDA算法对葡萄酒数据进行分类:

import pandas as pd
wine = pd.read_csv("葡萄酒数据集.csv")
y = wine["Class"]
x = wine.drop("Class",axis=1,inplace=False)
X= x.values
Y = y.values
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis,QuadraticDiscriminantAnalysis
from sklearn.metrics import accuracy_score
# 创建LDA模型对象
lda = LinearDiscriminantAnalysis()
# 训练LDA模型
lda.fit(X_train, y_train)
# 创建QDA模型对象
qda = QuadraticDiscriminantAnalysis()
# 训练QDA模型
qda.fit(X_train, y_train)

# 进行k-折交叉验证
from sklearn.model_selection import KFold
k=10
acc_lda = []
acc_qda=[]
# 初始化KFold对象
kf = KFold(n_splits=k, shuffle=True, random_state=42)
for train_index,test_index in kf.split(X):
    X_train,X_test = X[train_index],X[test_index]
    Y_train,Y_test = Y[train_index],Y[test_index]
    # 创建模型
    lda = LinearDiscriminantAnalysis()
    qda = QuadraticDiscriminantAnalysis()
    # 训练模型
    lda.fit(X_train,Y_train)
    qda.fit(X_train,Y_train)
    # 预测
    y_pre_lda = lda.predict(X_test)
    y_pre_qda = qda.predict(X_test)
    # 评估
    acc_lda.append(accuracy_score(y_pre_lda,Y_test))
    acc_qda.append(accuracy_score(y_pre_qda,Y_test))
print(acc_lda)
print(acc_qda)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ρ爱上θ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值