文章目录

  • 前言
  • 一、主成分分析(PCA)
  • 1.说明
  • 2.【例1】基于主成分分析对 Iris 数据集降维:
  • 二、奇异值分解(SVD)
  • 1.说明
  • 2.【例2】基于奇异值分解对 Iris 数据集降维。
  • 三、线性判别分析(LDA)
  • 1.说明
  • 2.【例3】基于线性判别式分析对 Iris 数据集降维
  • 四、局部线性嵌入(LLE)
  • 1.说明
  • 2.【例4】基于局部线性嵌入对 Iris 数据集降维
  • 五、拉普拉斯特征映射(LE)
  • 1.说明
  • 2.【例5】基于拉普拉斯特征映射的数据降维

 

前言

高维数据降维是指采用某种映射方法,降低随机变量的数量,例如将数据点从高维空间映射到低维空间中,从而实现维度减少。降维分为特征选择和特征提取两类,前者是从含有冗余信息以及噪声信息的数据中找出主要变量,后者是去掉原来数据,生成新的变量,可以寻找数据内部的本质结构特征。

降维的过程是通过对输入的原始数据特征进行学习,得到一个映射函数,实现将输入样本映射后到低维空间中之后,原始数据的特征并没有明显损失,通常情况下新空间的维度要小于原空间的维度。且前大部分降维算法是处理向量形式的数据。
本文列举了常用的一些降维方法,包括:无监督线性降维方法PCA;协助PCA的奇异值分解;有监督的线性降维算法LDA;非线性流形算法LLE与LE。
1.主成分分析(PCA)
2.奇异值分解(SVD)
3.线性判别分析(LDA)
4.局部线性嵌入(LLE)
5.拉普拉斯特征映射(LE)

一、主成分分析(PCA)

1.说明

主成分分析( Principal Component Analysis, PCA)是最常用的线性降维方法,在数据压缩消除冗余和数据噪音消除等领域都有广泛的应用。PCA是不考虑样本类别输出的无监督降维技术,它的目标是通过某种线性投影,将高维的数据映射到低维的空间中,并期望在所投影的维度上数据的方差最大,以此使用较少的维度,同时保留较多原数据的维度。
举个例子,如下图,将数据从二维降维到一维。希望找到某一个维度方向,它可以代表这两个维度的数据。图中列了两个向量方向,u1和u2,从直观上可以看出,u1比u2好,可以解释为一是样本点到这个直线的距离足够近,2二是样本点在这个直线上的投影能尽可能的分开。

plotly_express 高维 高维数据处理_plotly_express 高维

所以可以解释希降维的标准为:样本点到这个超平面的距离足够近,或者说样本点在这个超平面上的投影能尽可能的分开。
PCA 算法目标是求出样本数据的协方差矩阵的特征值和特征向量,而协方差矩阵的特征向量的方向就是PCA 需要投影的方向。使样本数据向低维投影后,能尽可能表征原始的数据。

2.【例1】基于主成分分析对 Iris 数据集降维:

本文章使用sklearn库中的Iris 数据集来进行数据降维实验。
该数据集特征包括鸢尾花的花萼长度、花萼宽度、花辦长度和花瓣觉度 4 个属性,还有列保存了鸢尾花的类型结果。
a.先查看数据的分布情况

#查看数据的分布情况:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import datasets
data = datasets.load_iris()
X =data['data']
y =data['target']
ax = Axes3D(plt.figure())
for c, i, target_name in zip('rgb', [0, 1, 2], data.target_names):
    ax.scatter(X[y==i, 0], X[y==i, 3], c=c, label=target_name) 
ax.set_xlabel(data.feature_names[0])
ax.set_xlabel(data.feature_names[1])
ax.set_xlabel(data.feature_names[2])
ax.set_xlabel(data.feature_names[3])
ax.set_title('Iris')
plt.legend()
plt.show()

plotly_express 高维 高维数据处理_数据集_02


可以发现红色数据点,也就是Setosa距离其他数据较远。

b.用pca将原本的数据降为二维,并在平面中画出样本点的分布。

#利用PCA将数据降到二维:
import matplotlib.pyplot as plt                
from sklearn.decomposition import PCA          
from sklearn.datasets import load_iris
data=load_iris()
y=data.target
x=data.data
pca=PCA(n_components=2)  #设置降维后的主成分数目为2。
reduced_x=pca.fit_transform(x)
red_x,red_y=[],[]
blue_x,blue_y=[],[]
green_x,green_y=[],[]
for i in range(len(reduced_x)):
    if y[i] ==0:
        red_x.append(reduced_x[i][0])
        red_y.append(reduced_x[i][1])
    elif y[i]==1:
        blue_x.append(reduced_x[i][0])
        blue_y.append(reduced_x[i][1])
    else:
        green_x.append(reduced_x[i][0])
        green_y.append(reduced_x[i][1])
plt.scatter(red_x,red_y,c='r',marker='x')
plt.scatter(blue_x,blue_y,c='b',marker='D')
plt.scatter(green_x,green_y,c='g',marker='.')
plt.show()

plotly_express 高维 高维数据处理_数据_03


可以看到三种类别的样本在二维比四维空间区分度更大,从PCA 的实现原理来看,这种变换并没有改变各样本之间的关系,只是应用了新的坐标系。如上是将四维空问转降到二维空间,如果有一个n维的数据,想要降低到k维。那么就取前k个特征值对应的特征向量即可。

二、奇异值分解(SVD)

1.说明

PCA 的主要缺点是当数据量和数据维数非常大的时候,用协方差矩阵的方法解 PCA 会变得非常低效,解决办法是采用奇异值分解 ( Singular Value Decomposition, SVD)技术。

对于任意mxn的输入矩阵 A,SVD 分解结果为:

plotly_express 高维 高维数据处理_plotly_express 高维_04

分解结果中U为左奇异矩阵,S为奇异值阵,除主对角线上的元素外全为0,主对角线上的每个元素都称为奇异值,V为右奇异矩阵。矩阵 U、V中的列向量均为正交单位向量,而矩阵S为对角阵,并且以从左上到右下以递减的顺序排序,可以直接借用SVD的结果来获取协方差矩阵的特征向量和特征值。

2.【例2】基于奇异值分解对 Iris 数据集降维。

numpy 库中已实现 SVD 方法,位于 linalg 模块中。
将 Iris 数据集的分类标签列排除,使用前 4 列数据作为linalg.svd()方法的输入进行计算,得到左奇异矩阵 U、奇异值矩阵 S、右奇异矩阵V。选择V中前2个特征分别作为二维平面的x,y坐标进行可视化。

import numpy as np
from numpy.linalg import svd
from sklearn import datasets 
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
iris = datasets.load_iris()
data_src = iris.data #(150,4)
labels = iris.target #(150,)
d = 2 #设置低维空间维数
data_cen = data_src - np.mean(data_src,axis=0) # 样本中心化处理
# 用 SVD(奇异值分解) 做PCA
def pca_svd():
  u, s, v = svd(data_cen)
  pc_svd = np.dot(data_cen, v[:,0:2])
  plt.scatter(pc_svd[:,0], pc_svd[:,1], c = labels)
  plt.show()
pca_svd()

plotly_express 高维 高维数据处理_数据集_05

三、线性判别分析(LDA)

1.说明

线性判别式分析(Linear Discriminant Analysis),简称为LDA,是模式识别的经典算法。是一种有监督的线性降维算法,与PCA不同的LDA是为了使降维后的数据点尽可能容易地被分开。
基本思想是将高维的模式样本投影到最佳鉴别矢量空间,以达到抽取分类信息和压缩特征空间维数的效果,投影后保证模式样本在新的子空间有最大的类间距离和最小的类内距离,即模式在该空间中有最佳的可分离性。
LDA与PCA都是常用的降维技术。PCA主要是从特征的协方差角度,去找到比较好的投影方式。LDA更多的是考虑了标注,即希望投影后不同类别之间数据点的距离更大,同一类别的数据点更紧凑。

2.【例3】基于线性判别式分析对 Iris 数据集降维

from sklearn import datasets
data = datasets.load_iris()
#print(data.head())
x =data['data']
y =data['target']
#首先计算数据集的平均向量,即计算每种类别下各输入特征的平均值:
class_labels = np.unique(y)
n_classes = class_labels.shape[0]
mean_vectors = []
for cl in class_labels:
  mean_vectors.append(np.mean(X[y==cl], axis=0))
mean_vectors

3个类别的平均向量计算结果存于数组变量 mean_ vectors 中

[array([5.006, 3.428, 1.462, 0.246]),
 array([5.936, 2.77 , 4.26 , 1.326]),
 array([6.588, 2.974, 5.552, 2.026])]
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
import pandas as pd
data = datasets.load_iris()
x =data['data']
y =data['target']
target_names = data.target_names
pd.DataFrame(x, columns=data.feature_names).head()
lda = LinearDiscriminantAnalysis(n_components=2)
X_r2 = lda.fit(X, y).transform(X)
plt.figure()
colors = ['navy', 'turquoise', 'darkorange']
lw = 2
for color, i, target_name in zip(colors, [0, 1, 2], target_names):
    plt.scatter(X_r2[y == i, 0], X_r2[y == i, 1], alpha=.8, color=color,
                label=target_name)
plt.legend(loc='best', shadow=False, scatterpoints=1)
plt.title('LDA')
plt.show()

plotly_express 高维 高维数据处理_数据集_06

四、局部线性嵌入(LLE)

1.说明

局部线性嵌入是一种典型的非线性降维算法,LLE关注于降维时保持样本局部的线性关系,广泛的用于图像识别、高维数据可视化等领域。这一算法要求每一个数据点都可以由其近邻点的线性加权组合构造得到,从而使降维后的数据也能基本保持原有流形结构。它是流形学习方法最经典的工作之一,后续的很多流形学习、降维方法都与其有密切联系。
局部线挫缺入寻求数据的低维投影,保留本地邻域内的距离。它可以被认为是一系列局部主成分分析,被全局比较以找到最佳的非线性嵌入。
算法的主要步骤分为三步:首先寻找每个样本点的 k个近邻点;然后,由每个样本点的近邻点计算出该样本点的局部重建权值矩阵;最后,由该样本点的局部重建权值矩阵和近邻点计算出该样本点的输出值。
LLE在有些情况下也并不适用,例如数据分布在整个封闭的球面上,LLE 则不能将它映射到二维空间,旦不能保特原有的数据流形。因此在处理数据时,需要确保数据不是分布在闭合的球面或者椭球面上。

2.【例4】基于局部线性嵌入对 Iris 数据集降维

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets,decomposition,manifold
#加载数据
def load_data():
    iris=datasets.load_iris()
    return iris.data,iris.target
    def test_LocallyLinearEmbedding(*data):
    X,y=data
    for n in [4,3,2,1]:
        lle=manifold.LocallyLinearEmbedding(n_components=n)
        lle.fit(X,y)
        print('reconstruction_error(n_components=%d):%s'%(n,lle.reconstruction_error_))

X,y=load_data()
test_LocallyLinearEmbedding(X,y)
reconstruction_error(n_components=4):1.7884357002646582e-06
reconstruction_error(n_components=3):3.99290585563583e-07
reconstruction_error(n_components=2):6.641420805446877e-08
reconstruction_error(n_components=1):-2.509129594561617e-15

降维后样本的分布图

def plot_LocallyLinearEmbedding(*data):
    X,y=data
    Ks=[1,5,25,y.size-1]
    fig=plt.figure()
    for i,k in enumerate(Ks):
        lle=manifold.LocallyLinearEmbedding(n_components=2,n_neighbors=k)
        X_r=lle.fit_transform(X)
        ax=fig.add_subplot(2,2,i+1)
        colors=((1,0,0),(0,1,0),(0,0,1),(0.5,0.5,0),(0,0.5,0.5),(0.5,0,0.5),
               (0.4,0.6,0),(0.6,0.4,0),(0,0.6,0.4),(0.5,0.3,0.2),)
        for label,color in zip(np.unique(y),colors):
            position=y==label         ax.scatter(X_r[position,0],X_r[position,1],label='target=%d'%label,color=color)
        ax.set_xlabel('X[0]')
        ax.set_ylabel('X[1]')
        ax.legend(loc='best')
        ax.set_title("k=%d"%k)
    plt.suptitle('LocallyLinearEmbadding')
    plt.show()
plot_LocallyLinearEmbedding(X,y)

plotly_express 高维 高维数据处理_数据_07


将原始数据的特征直接压缩到一维

def plot_LocallyLinearEmbedding_k_d1(*data):
    X,y=data
    Ks=[1,5,25,y.size-1]
    fig=plt.figure()
    for i,k in enumerate(Ks):
        lle=manifold.LocallyLinearEmbedding(n_components=2,n_neighbors=k)
        X_r=lle.fit_transform(X)
        ax=fig.add_subplot(2,2,i+1)
        colors=((1,0,0),(0,1,0),(0,0,1),(0.5,0.5,0),(0,0.5,0.5),(0.5,0,0.5),
               (0.4,0.6,0),(0.6,0.4,0),(0,0.6,0.4),(0.5,0.3,0.2),)
        for label,color in zip(np.unique(y),colors):
            position=y==label           ax.scatter(X_r[position],np.zeros_like(X_r[position]),label='target=%d'%label,color=color)
        ax.set_xlabel('X[0]')
        ax.set_ylabel('Y')
        ax.legend(loc='best')
        ax.set_title("k=%d"%k)
    plt.suptitle('LocallyLinearEmbedding')
    plt.show()
plot_LocallyLinearEmbedding_k_d1(X,y)

plotly_express 高维 高维数据处理_二维_08

五、拉普拉斯特征映射(LE)

1.说明

拉普拉斯特征映射其思路和LLE很相似,也是基于图的降维算法,希望相互关联的点降维后的空间尽可能靠近,通过构建邻接矩阵,最后推导,矩阵分解等步骤,实现降维。

2.【例5】基于拉普拉斯特征映射的数据降维

a.通过sklearn库中的make_swiss_roll()方法生成瑞士卷形状的测试样本,同时调用view_init方法调整三维视角

from sklearn import manifold, datasets
import numpy as np
import matplotlib.pyplot as plt
X,color = datasets.make_swiss_roll(n_samples = 1500)
ax = plt.subplot(projection = '3d')
# 原始数据
ax.scatter(X[:,0],X[:,1],X[:,2],c = color, cmap=plt.cm.Spectral)  
# 调整三维视角
ax.view_init(4,-50)

plotly_express 高维 高维数据处理_plotly_express 高维_09


b.对原始样本进行LE降维

sklearn库中,拉普拉斯特征映射是在SpectralEmbadding类中实现的,其参数n_components和n_neighbors分别表示目标子空间的特征数量(维度)和构建无向图时的最近邻数量。初始化se对象之后调用fit_transform()方法将原始样本投射到新的子空间。

#2维10个近邻点
se = manifold.SpectralEmbedding(n_components=2,n_neighbors=10)
# 将原始样本投射到新的子空间中
Y = se.fit_transform(X)  

# LE 降维后可视化
plt.scatter(Y[:,0],Y[:,1],c=color,cmap=plt.cm.Spectral)

plotly_express 高维 高维数据处理_数据_10


对比原始样本在三维空间和降维之后在二维空间的分布情况,可以看到,在高维和低维空间中的样本分布形状发生了变化,但降维后样本之间的联系并没有变。