从零开始实现线性判别分析(LDA)算法(多类情形)
来源:互联网 发布:python网络编程 amazon 编辑:程序博客网 时间:2024/05/01 09:57
声明:版权所有,转载请联系作者并注明出处:
http://blog.csdn.net/u013719780?viewmode=contents
知乎专栏:
https://www.zhihu.com/people/feng-xue-ye-gui-zi/columns
前文详细阐述了只有二类的情形,假设如果是多类情形,该怎么处理才能保证投影后的类别能够较好的分离呢?
我们之前讨论的是如何将
则有
将
定义每个子集的中心:
若是多类别,相关符号与二类别类似(详见上篇文章),其中子集
总体样本均值:
类内离散度矩阵定义类似:
需要注意的是,类间离散度矩阵的定义有些不同,回想我们二值类型情形时的公式
当然还有另一种类间类内的离散度矩阵表达方式:
其中
我们可以知道矩阵
LDA做为一个分类的算法,我们当然希望它所分的类之间耦合度低,类内的聚合度高,即类内离散度矩阵的中的数值要小,而类间离散度矩阵中的数值要大,这样的分类的效果才好。
与上一篇文章类似,我们引入Fisher判别准则表达式,即损失函数:
由于我们得到的分子分母都是散列矩阵,要将矩阵变成实数,需要取行列式。又因为行列式的值实际上是矩阵特征值的积,一个特征值可以表示在该特征向量上的发散程度。因此我们使用行列式来计算(此处我感觉有点牵强,道理不是那么有说服力)。整个问题又回归为求
我们的目标就是通过最优化(5)式,找到有一组最优鉴别矢量构成的投影矩阵(这里我们也可以看出1/m可以通过分子分母约掉,所以前面所提到的第一组公式和第二组公式所表达的效果是一样的)。
可以证明,当为
将(7)式代入(6)式可得,
很明显,只需要取绝对值比较大的
注意:由于
由于
算法流程
输入:数据集
输出:降维后的样本集
计算类内散度矩阵
Sw 和类间散度矩阵SB ;计算矩阵
S−1wSB 的特征值;找出矩阵
S−1wSB 最大的k 个特征值和其对应的k 个特征向量(w1,w2,...,wk) ;将原始样本集投影到以
(w1,w2,...,wk) 为基向量生成的低维空间中(k维),投影后的样本集就是我们需要的样本集D' 。
LDA算法总结
LDA算法既可以用来降维,又可以用来分类,但是目前来说,主要还是用于降维。在我们进行图像识别图像识别相关的数据分析时,LDA是一个有力的工具。下面总结下LDA算法的优缺点。
LDA算法的主要优点有:
LDA是监督学习,在分类和降维过程中利用了类别的先验知识,而像PCA这样的无监督学习则无法使用类别先验知识。
LDA在样本分类信息依赖均值而不是方差的时候,比PCA之类的降维算法效果更好。
缺点
LDA至多投影到
nlabels−1 维子空间;LDA不适合对非高斯分布样本进行降维;
上图中红色区域表示一类样本,蓝色区域表示另一类,由于是2类,所以最多投影到1维上。不管在直线上怎么投影,都难使红色点和蓝色点内部凝聚,类间分离。
- LDA在样本分类信息依赖方差而不是均值时,效果不好;
上图中,样本点依靠方差信息进行分类,而不是均值信息。LDA不能够进行有效分类,因为LDA过度依靠均值信息。
LDA可能过度拟合数据;
LDA在非线性情形效果不好。
LDA的一些变种
1、 非参数LDA
非参数LDA使用本地信息和
2、 正交LDA
先找到最佳的特征向量,然后找与这个特征向量正交且最大化
3、 一般化LDA
引入了贝叶斯风险等理论
4、 核函数LDA
将特征做变换
from __future__ import print_functionimport scipyfrom sklearn import datasetsimport matplotlib.pyplot as plt%matplotlib inlineimport numpy as npdef shuffle_data(X, y, seed=None): if seed: np.random.seed(seed) idx = np.arange(X.shape[0]) np.random.shuffle(idx) return X[idx], y[idx]# 正规化数据集 Xdef normalize(X, axis=-1, p=2): lp_norm = np.atleast_1d(np.linalg.norm(X, p, axis)) lp_norm[lp_norm == 0] = 1 return X / np.expand_dims(lp_norm, axis)# 标准化数据集 Xdef standardize(X): X_std = np.zeros(X.shape) mean = X.mean(axis=0) std = X.std(axis=0) # 做除法运算时请永远记住分母不能等于0的情形 # X_std = (X - X.mean(axis=0)) / X.std(axis=0) for col in range(np.shape(X)[1]): if std[col]: X_std[:, col] = (X_std[:, col] - mean[col]) / std[col] return X_std# 划分数据集为训练集和测试集def train_test_split(X, y, test_size=0.2, shuffle=True, seed=None): if shuffle: X, y = shuffle_data(X, y, seed) n_train_samples = int(X.shape[0] * (1-test_size)) x_train, x_test = X[:n_train_samples], X[n_train_samples:] y_train, y_test = y[:n_train_samples], y[n_train_samples:] return x_train, x_test, y_train, y_testdef accuracy(y, y_pred): y = y.reshape(y.shape[0], -1) y_pred = y_pred.reshape(y_pred.shape[0], -1) return np.sum(y == y_pred)/len(y)# 计算矩阵X的协方差矩阵def calculate_covariance_matrix(X, Y=np.empty((0,0))): if not Y.any(): Y = X n_samples = np.shape(X)[0] covariance_matrix = (1 / (n_samples-1)) * (X - X.mean(axis=0)).T.dot(Y - Y.mean(axis=0)) return np.array(covariance_matrix, dtype=float)class MultiClassLDA(): """ 线性判别分析分类算法(Linear Discriminant Analysis classifier). 既可以用来分类也可以用来降维. 此处实现二类情形(二类情形分类). Parameters: ----------- solver: str 若 solver = 'svd', 则使用SVD(奇异值分解)方法求解矩阵伪逆; 否则直接求解矩阵的逆. eigen_values: 矩阵SW^(-1).dot(SB)的特征值. eigen_vectors: 矩阵SW^(-1).dot(SB)的特征值所对应的特征向量. k: int 投影空间(低维空间)的维度. """ def __init__(self, solver="svd"): self.solver = solver self.eigen_values = None self.eigen_vectors = None self.k = 2 def calculate_scatter_matrices(self, X, y): n_features = np.shape(X)[1] labels = np.unique(y) # 计算类内散布矩阵:SW = sum{sum{(Xi^(k) - Xi_mean).dot((Xi^(k) - Xi_mean).T)}for k}for i # 和类间散布矩阵: SB = sum{ ni * (Xi_mean - X_mean).dot((Xi_mean - X_mean).T) } SW = np.empty((n_features, n_features)) SB = np.empty((n_features, n_features)) X_mean = X.mean(axis=0) for label in labels: Xi = X[y == label] SW = SW + (Xi.shape[0] - 1) * calculate_covariance_matrix(Xi) Xi_mean = Xi.mean(axis=0) SB = SB + Xi.shape[0] * (Xi_mean - X_mean).dot((Xi_mean - X_mean).T) return SW, SB def transform(self, X, y): SW, SB = self.calculate_scatter_matrices(X, y) # 使用SVD(奇异值分解)求解SW伪逆. if self.solver == "svd": # Calculate SW^-1 * SB by SVD (pseudoinverse of diagonal matrix S) U, S, V = np.linalg.svd(SW) S = np.diag(S) SW_inverse = V.dot(np.linalg.pinv(S)).dot(U.T) A = SW_inverse.dot(SB) # 直接求解矩阵SW的逆矩阵. else: A = np.linalg.inv(SW).dot(SB) # 求解矩阵A的特征值和对应的特征向量 self.eigen_values, self.eigen_vectors = np.linalg.eigh(A) # 将特征值按照其绝对值从大到小进行排序(因为SW, SB是对称阵, 故A也是对称阵, # 因此A的特征值是非负的), 取其前k个特征值以及对应的k个特征向量 idx = self.eigen_values.argsort()[::-1] topk_eigen_values = self.eigen_values[idx][:self.k] topk_eigen_vectors = self.eigen_vectors[:, idx][:, :self.k] # 将样本投影到低维空间 X_transformed = X.dot(topk_eigen_vectors) return X_transformed # Plot the dataset X and the corresponding labels y in 2D using the LDA # transformation. def visualization(self, X, y, title=None): X_transformed = self.transform(X, y) x1 = X_transformed[:, 0] x2 = X_transformed[:, 1] plt.scatter(x1, x2, c=y) if title: plt.title(title) plt.show()def main(): # Load the dataset data = datasets.load_iris() X = normalize(data.data) y = data.target # Project the data onto the 2 primary components multi_class_lda = MultiClassLDA() multi_class_lda.visualization(X, y, title="LDA")if __name__ == "__main__": main()
参考文献:
刘建平Pinard:http://www.cnblogs.com/pinard/p/6244265.html
JerryLead:http://www.cnblogs.com/jerrylead/archive/2011/04/21/2024389.html
- 从零开始实现线性判别分析(LDA)算法(多类情形)
- 从零开始实现线性判别分析(LDA)算法(二类情形)
- 线性判别分析LDA算法
- 线性判别分析算法(LDA)
- 线性判别分析(LDA)算法
- LDA(线性判别分析)算法
- LDA-线性判别分析(三)推广到 Multi-classes 情形
- 线性判别分析LDA的多个python实现
- LDA 两类Fisher线性判别分析及python实现
- 线性判别分析(LDA)算法总结
- LDA(线性判别分析)算法入门
- 机器学习算法03-线性判别分析LDA
- 降维算法:线性判别分析LDA
- LDA(线性判别分析)及源码实现
- 使用LDA线性判别分析进行多类的训练分类
- 使用LDA线性判别分析进行多类的训练分类
- 线性判别分析(LDA)
- LDA 线性判别分析
- 身体各个时辰的变化
- 博客访问破万纪念
- TabLayout+ViewPager的基本使用
- Httpurl网络获取数据
- 实验3.5 十进制转换
- 从零开始实现线性判别分析(LDA)算法(多类情形)
- DBDT 基于不同损失函数的算法推导细节
- swift方法实现字符串的大小写转换
- Sap BussinessObjects Design Studio-infoChart
- 高手详解SQL性能优化十条经验
- Volume-Docker存储(一)
- JPA-Java Persistence API
- Spring中ApplicationContext和beanfactory区别
- 进程