浏览本文须要的背景知识点:线性判别分析、一丢丢编程常识
一、引言
后面两节介绍了线性判别分析在不同角度下的实现形式,一种是依据费舍尔“类内小、类间大”的角度,另一种则是从概率分布的角度。本节来介绍另一种判别分析——二次判别分析算法1(Quadratic Discriminant Analysis Algorithm/QDA)
二、模型介绍
同线性判别分析一样,从概率分布的角度来失去二次判别分析,区别在于线性判别分析假如每一种分类的协方差矩阵雷同,而二次判别分析中每一种分类的协方差矩阵不同。
(1)同线性判别分析一样,咱们的目标就是求在输出为x的状况下分类为k的概率最大的分类,所以咱们能够写出假如函数如下图(1)式
(2)对其概率取对数,不影响函数的最初后果
(3)带入下面的P(k|x)的表达式,因为P(x)对最初后果也没有影响,也能够间接去掉
(4)带入多元正态分布的概率密度函数表达式,留神这里与线性判别分析的不同,协方差矩阵在每一种类型下是不同的
(5)将(4)式中的对数化简失去
(6)这时就不能和线性判别分析一样去掉第二项了,而是要保留其中协方差矩阵行列式的局部,失去最初的后果
$$\begin{aligned}h(x) &=\underset{k}{\operatorname{argmax}} P(k \mid x) & (1)\\&=\underset{k}{\operatorname{argmax}} \ln P(k \mid x) & (2)\\&=\underset{k}{\operatorname{argmax}} \ln f_{k}(x)+\ln P(k) & (3) \\&=\underset{k}{\operatorname{argmax}} \ln \left(\frac{e^{-\frac{\left(x-\mu_{k}\right)^{T}{\Sigma_{k}^{-1}\left(x-\mu_{k}\right)}}{2}}}{\left|\Sigma_{k}\right|^{\frac{1}{2}}(2 \pi)^{\frac{p}{2}}}\right)+\ln P(k) & (4) \\&=\underset{k}{\operatorname{argmax}} -\frac{1}{2}\left(x-\mu_{k}\right)^{T} \Sigma_{k}^{-1}\left(x-\mu_{k}\right)-\ln \left(\left|\Sigma_{k}\right|^{\frac{1}{2}}(2 \pi)^{\frac{p}{2}}\right)+\ln P(k) & (5) \\&=\underset{k}{\operatorname{argmax}} -\frac{1}{2}\left(x-\mu_{k}\right)^{T} \Sigma_{k}^{-1}\left(x-\mu_{k}\right)-\frac{1}{2} \ln \left(\left|\Sigma_{k}\right|\right)+\ln P(k) & (6)\end{aligned}$$
察看下面的(6)式,可知是对于x的二次函数,所以这也是该算法被称为二次判别分析算法的起因。
三、代码实现
应用 Python 实现二次判别分析(QDA):
def qda(X, y): """ 二次判别分析(QDA) args: X - 训练数据集 y - 指标标签值 return: y_classes - 标签类别 priors - 每类先验概率 means - 每类均值向量 sigmags - 每类协方差矩阵 dets - 每类协方差矩阵行列式 """ # 标签值 y_classes = np.unique(y) # 每类先验概率 priors = [] # 每类均值向量 means = [] # 每类协方差矩阵 sigmags = [] # 每类协方差矩阵行列式 dets = [] for idx in range(len(y_classes)): c = X[y==y_classes[idx]][:] # 先验概率 prior = c.shape[0] / X.shape[0] priors.append(prior) # 均值向量 mu = np.mean(c, axis=0) means.append(mu) # 协方差矩阵 sigma = c - mu sigma = sigma.T.dot(sigma) / c.shape[0] sigmags.append(np.linalg.pinv(sigma)) # 协方差矩阵行列式 dets.append(np.linalg.det(sigma)) return y_classes, priors, means, sigmags, detsdef discriminant(X, y_classes, priors, means, sigmags, dets): """ 判断新样本点 args: X - 数据集 y_classes - 标签类别 priors - 每类先验概率 means - 每类均值向量 sigmags - 每类协方差矩阵 dets - 每类协方差矩阵行列式 return: 分类后果 """ ps = [] for idx in range(len(y_classes)): x = X - means[idx] p = - 0.5 * (np.sum(np.multiply(x.dot(sigmags[idx]), x), axis=1) + np.log(dets[idx])) + priors[idx] ps.append(p) return y_classes.take(np.array(ps).T.argmax(1))
四、第三方库实现
scikit-learn2 实现线性判别分析:
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis# 初始化二次判别分析器qda = QuadraticDiscriminantAnalysis()# 拟合数据qda.fit(X, y)# 预测数据qda.predict(X)
sklearn的实现并没有像下面的实现一样间接去计算协方差矩阵的逆矩阵,而是通过奇怪值合成(SVD)的形式防止间接求协方差矩阵的逆矩阵,计算复杂度会小很多,具体可参考sklearn文档3 中对协方差矩阵的预计算法。
五、动画演示
下图展现了存在二种分类时的演示数据,其中红色示意标签值为0的样本、蓝色示意标签值为1的样本:
上面两张图别离展现了线性判别分析和二次判别分析拟合数据的后果,其中浅红色示意拟合后依据权重系数计算出预测值为0的局部,浅蓝色示意拟合后依据权重系数计算出预测值为1的局部:
能够很显著的看到两种判别分析的决策边界的不同,线性判别分析只能学习线性边界,而二次判别分析能够学习二次边界,因而具备更大的灵活性。
六、思维导图
七、参考文献
- https://en.wikipedia.org/wiki...
- https://scikit-learn.org/stab...
- https://scikit-learn.org/stab...
残缺演示请点击这里
注:本文力求精确并通俗易懂,但因为笔者也是初学者,程度无限,如文中存在谬误或脱漏之处,恳请读者通过留言的形式批评指正
本文首发于——AI导图,欢送关注