网上各种降维算法资料参差不齐,大多不提供源码.这里有一个使用Python实现11种经典数据提取(数据降维)算法的GitHub项目,包括:PCA、LDA、MDS、LLE、TSNE等,并附有相关资料和展示效果;非常适合机器学习初学者和刚开始数据挖掘的人。为什么要进行数据降维?所谓降维是指用一组维数为d的向量Zi来表示一个维数为D的向量Xi中包含的有用信息。通常我们会发现大部分数据集的维数会是高达数百甚至数千,而经典的MNIST维度为64。MNIST手写数字数据集,但在实际应用中,我们使用的有用信息并不需要这么高的维度,每增加一个维度所需的样本数呈指数增长,这可能会直接带来极大的“维度诅咒”;可以实现数据降维:使数据集更易于使用,保证变量相互独立,降低算法的计算成本,去除噪声。大大有助于减少计算量,从而提高机器运行效率。数据降维也常用于文本处理、人脸识别、图像识别、自然语言处理等领域。数据降维的原理往往是高维空间中的数据会稀疏分布,所以在降维处理的过程中,我们通常会做一些数据删除,包括冗余数据、无效信息、重复表达内容等.例如:有一张1024*1024的图片,除了中心50*50的区域,其他位置都是零值,这些零信息可以归类为无用信息;对于对称图形,对称部分的信息可以归类为重复信息。因此,大部分经典的降维技术也是基于这个内容。降维方法分为线性降维和非线性降维,非线性降维又分为基于核函数的方法和基于特征值的方法。线性降维方法:PCA、ICALDA、LFA、LPP(LE的线性表示)非线性降维方法:基于核函数的非线性降维方法-KPCA、KICA、KDA基于特征值的非线性降维方法(流式学习)-ISOMAP,LLE,LE,LPP,LTSA,MVUHeucoder哈尔滨工业大学计算机技术专业硕士生,整理了PCA,KPCA,LDA,MDS,ISOMAP,LLE,TSNE,AutoEncoder,FastICA,有12个提供SVD、LE、LPP等经典降维算法,并提供相关资料、代码和展示。下面将主要以PCA算法为例介绍降维算法的具体操作。PrincipalComponentAnalysis(PCA)降维算法PCA是一种基于从高维空间映射到低维空间的映射方法,也是最基本的无监督降维算法。朝着最小化重建误差的方向投射。由KarlPearson于1901年提出,属于线性降维方法。与PCA相关的原理通常称为最大方差理论或最小误差理论。两者的目标相同,只是过程的侧重点不同。最大方差理论的降维原理将一组N维向量降为K维(K大于0且小于N)。目标是选择K个单位正交基,每个域之间的COV(X,Y)为0,域的方差尽可能大。因此,最大方差就是最大化投影数据的方差。在这个过程中,我们需要找到数据集Xmxn的最佳投影空间Wnxk和协方差矩阵。算法流程为:算法输入:数据集Xmxn;按列计算数据集X的均值Xmean,然后设Xnew=X?Xmean;求解矩阵Xnew的协方差矩阵,记为Cov;计算协方差矩阵COv的特征值和对应的特征向量;按照从大到小的排序,选取其中最大的k个,然后将对应的k个特征向量作为列向量,组成特征向量矩阵Wnxk;计算XnewW,即将数据集Xnew投影到选定的特征向量上,这样我们就得到了我们需要的降维数据集XnewW。最小误差理论降维原理和最小误差是使平均投影代价最小的线性投影。在这个过程中,我们需要找到平方误差评价函数J0(x0)等参数。详细步骤可参考《从零开始实现主成分分析 (PCA) 算法》:https://blog.csdn.net/u013719780/article/details/78352262主成分分析(PCA)代码实现关于PCA算法的代码如下:from__future__importprint_functionfromsklearnimportdatasetsimportmatplotlib.pyplotaspltimportmatplotlib.cmascmximportmatplotlib.colorsascolorsimportnumpyasnp%matplotlibinlinedefshuffle_data(X,y,seed=None):ifseed:np.random.seed(seed)idx=np.arange(X.shape[0])np.random.shuffle(idx)returnX[idx],y[idx]#NormalizethedatasetXdefnormalize(X,axis=-1,p=2):lp_norm=np.atleast_1d(np.linalg.norm(X,p,axis))lp_norm[lp_norm==0]=1returnX/np.expand_dims(lp_norm,axis)#StandardizeddatasetXdefstandardize(X):X_std=np.zeros(X.shape)mean=X.mean(axis=0)std=X.std(axis=0)#Whendoingdivisionoperation,pleaseAlwaysrememberthatthedenominatorcannotbeequalto0#X_std=(X-X.mean(axis=0))/X.std(axis=0)forcolinrange(np.shape(X)[1]):ifstd[col]:X_std[:,col]=(X_std[:,col]-mean[col])/std[col]returnX_std#Dividethedatasetintotrainingsetandtestsetdeftrain_test_split(X,y,test_size=0.2,shuffle=True,seed=None):ifshuffle: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:]returnx_train,x_test,y_train,y_test#计算矩阵X的协方差矩阵defcalculate_covariance_matrix(X,Y=np.empty((0,0))):ifnotY.any:Y=Xn_samples=np.shape(X)[0]covariance_matrix=(1/(n_samples-1))*(X-X.mean(axis=0)).T.dot(Y-Y.mean(axis=0))returnnp.array(covariance_matrix,dtype=float)#计算数据集X每一列的方差defcalculate_variance(X):n_samples=np.shape(X)[0]variance=(1/n_samples)*np.diag((X-X.mean(axis=0)).T.dot(X-X.mean(axis=0)))returnvariance#计算数据集X每一列的标准差defcalculate_std_dev(X):std_dev=np.sqrt(calculate_variance(X))returnstd_dev#计算相关系数矩阵defcalculate_correlation_matrix(X,Y=np.empty([0])):#先计算协方差矩阵covariance_matrix=calculate_covariance_matrix(X,Y))#计算X,Y标准差std_dev_X=np.expand_dims(calculate_std_dev(X),1)std_dev_y=np.expand_dims(calculate_std_dev(Y),1)correlation_matrix=np.divide(covariance_matrix,std_dev_X.dot(std_dev_y.T))returnnp.matrix_array(xcorrelation,dtype=float)classPCA:"""主成分分析算法PCA,无监督学习算法。"""def__init__(self):self.eigen_values=Noneself.eigen_vectors=Noneself.k=2deftransform(self,X):"""通过PCA对原始数据集X进行约化"""covariance=calculate_covariance_matrix(X)#求解特征值和特征向量self.eigen_values,self.eigen_vectors=np.linalg.eig(covariance)#将特征值从大到小排序,注意特征向量是按列排列的,即第k个self.eigen_vectors列是self.eigen_valuesidx=self.eigen_values.argsort[::-1]eigenvalues=self.eigen_values[idx][:self.k]eigenvectors=self中第k个特征值对应的特征向量。eigen_vectors[:,idx][:,:self.k]#将原始数据集X映射到低维空间X_transformed=X.dot(eigenvectors)returnX_transformeddefmain:#Loadthedatasetdata=datasets.load_irisX=data.datay=data.target#Map数据集X到低维空间X_trans=PCA.transform(X)x1=X_trans[:,0]x2=X_trans[:,1]cmap=plt.get_cmap('viridis')colors=[cmap(i)foriinnp.linspace(0,1,len(np.unique(y)))]class_distr=#Plotthedifferentclassdistributionsfori,linenumerate(np.unique(y)):_x1=x1[y==l]_x2=x2[y==l]_y=y[y==l]class_distr.append(plt.scatter(_x1,_x2,color=colors[i]))#Addalegendplt.legend(class_distr,y,loc=1)#Axislabelsplt.xlabel('PrincipalComponent1')plt.ylabel('PrincipalComponent2')plt.showif__name__=="__main__":main最后我们会得到降维结果为接下来,如果特征个数(D)远大于样本个数(N),可以使用一个小技巧来实现PCA算法的复杂度转换。PCA降维算法展示当然,这个算法虽然经典常用,但是它的缺点也非常明显。可以很好的去除线性相关,但面对高阶相关效果较差;同时,PCA实现的前提是假设数据的主要特征分布在正交方向,所以对于非正交方向有几个方差较大的方向,PCA的效果会大打折扣.其他降维算法及代码地址KPCA(kernelPCA)KPCA是核技术与PCA相结合的产物。它与PCA的主要区别在于计算协方差矩阵时使用了核函数,即核函数映射后的协方差矩阵。核函数的引入可以很好的解决非线性数据映射问题。kPCA可以将非线性数据映射到一个高维空间,在高维空间使用标准PCA将其映射到另一个低维空间。KPCA降维算法展示详见《Python 机器学习》特征提取-kPCA:https://blog.csdn.net/weixin_40604987/article/details/79632888代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/blob/master/codes/PCA/KPCA.pyLDA(线性判别分析)LDA是一种可以用作特征提取的技术。分类等任务是为了有效地分离不同类别的样本。LDA可以提高数据分析过程中的计算效率,对于不能正则化的模型,可以减少维数灾难带来的过拟合。LDA降维算法的细节可以参考:https://blog.csdn.net/ChenVast/article/details/79227945代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/tree/master/codes/LDAMDS(multidimensionalscaling)MDS即多维尺度分析,是一种传统的降维方法,通过直观的空间图表达对研究对象的感知和偏好。该方法计算任意两个样本点之间的距离,使得投影到低维空间后可以保持相对距离,实现投影。由于sklearn中的MDS采用迭代优化的方式,下面分别实现迭代和非迭代两种。MDS降维算法展示详见《MDS 算法》https://blog.csdn.net/zhangweiguo_717/article/details/69663452代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/tree/master/codes/MDSISOMAPIsomap是等效的度量映射算法,可以很好地解决MDS算法在非线性结构化数据集上的弊端。MDS算法保持降维后样本间的距离不变,而Isomap算法引入了邻域图,样本只与其相邻样本相连,计算相邻点间的距离,然后在此基础上进行降维.距离。ISOMAP降维算法显示细节可以参考《Isomap》https://blog.csdn.net/zhangweiguo_717/article/details/69802312代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/tree/master/codes/ISOMAPLLE(locallylinearembedding)LLE是一种局部线性嵌入算法,是一种非线性降维算法。该算法的核心思想是每个点都可以通过与其相邻的多个点的线性组合来近似重构,然后将高维数据投影到低维空间中,使其保持数据之间的局部线性重构点关系,即具有相同的重建系数。在处理所谓的流形降维时,效果比PCA要好很多。LLE降维算法的展示详见《LLE 原理及推导过程》https://blog.csdn.net/scott198510/article/details/76099630代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/tree/master/codes/LLEt-SNEt-SNE也是一种非线性降维算法,非常适合将高维数据降维为2D或3D进行可视化。它是一种无监督的机器学习算法,根据数据的原始趋势重建低纬度(二维或三维)的数据趋势。下图的结果参考了源码,也可以在tensorflow中实现(无需手动更新参数)。t-SNE降维算法展示详情可以参考《t-SNE 使用过程中的一些坑》:http://bindog.github.io/blog/2018/07/31/t-sne-tips/代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/tree/master/codes/T-SNELE(LaplacianEigenmaps)LE就是拉普拉斯特征图,有点类似于LLE算法,也是从局部的角度构建数据之间的关系。它的直观想法是希望相互关联的点(图中的连通点)在降维空间中尽可能靠近;这样就可以得到一个能够反映流形几何结构的解。LE降维算法展示细节可以参考《拉普拉斯特征图降维及其 python 实现》:https://blog.csdn.net/HUSTLX/article/details/50850342代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/tree/master/代码/LELPP(LocalityPreservingProjections)LPP是局部保持投影算法。它的思想类似于拉普拉斯特征映射。其核心思想是通过最好地维护数据集的邻域结构信息来构建投影图,但LPP不同于LE直接得到投影结果,它需要求解投影矩阵。LPP降维算法的展示详见《局部保留投影算法 (LPP) 详解》:https://blog.csdn.net/qq_39187538/article/details/90402961代码地址:https://github.com/heucoder/dimensionality_reduction_alo_codes/tree/master/codes/LPP*《dimensionality_reduction_alo_codes》项目的作者Heucoder目前是哈尔滨工业大学计算机技术专业的硕士生。他主要活跃于互联网领域。知乎绰号“超爱学习”。他的github主页地址是:https://github.com/heucoder。Github项目地址:https://github.com/heucoder/dimensionality_reduction_alo_codes
