在这篇文章中我将介绍有关降维的一些东西,其中包括一些常见降维方法的概念、用途、优缺点以及python代码。
一、概念
降维是机器学习中常用到的一种技术,其用于减少数据集的维度,但又能保存数据集的重要信息,从而简化数据的处理,并提高计算效率、调高模型的性能以及方便可视化。
二、分类
降维可以分为两类,一类是线性降维,一类是非线性降维。
首先我们看线性降维,常见的算法有这几种:主成分分析(PCA)、线性判别分析(LDA)、因子分析(FA)、独立成分分析(ICA)等。
然后看非线性降维,常见的算法有这些:核主成分分析(KPCA)、非负矩阵分解(NMF)、等度量映射(Isomap)、局部线性嵌入(LLE)、t-分布随机邻域嵌入(t-SNE)、多维缩放(MDS)、拉普拉斯特征映射等。
三、算法详解
关于上述的几种算法,在这里将依次介绍。
3.1 PCA
首先是PCA,但是关于它我在之前的文章中有介绍,所以在这里我只用一句话来概括就是:PCA(主成分分析)是一种线性降维技术,通过将数据转换到新的坐标轴上并保留最大方差的方向来降低数据的维度,从而最大化信息保留的同时减少数据的复杂性。
此外,在这里我再附上一份PCA的代码,其内容为通过PCA将手写数字数据降维,并用特征值来绘制出一份图来,代码如下:
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
digits = load_digits()
# 数据集实例图像
fig, axes = plt.subplots(2, 5, figsize=(10, 5),
subplot_kw={'xticks':(), 'yticks':()})
for ax, img in zip(axes.ravel(), digits.images):
ax.imshow(img)
plt.show()
# PCA
pca = PCA(n_components=2)
pca.fit(digits.data)
digits_pca = pca.transform(digits.data)
colors = [
"#FF6347", # 热带橙红
"#00BFFF", # 亮青绿色
"#4682B4", # 明亮的蓝宝石色
"#BA55D3", # 亮紫罗兰色
"#FFD700", # 亮金色
"#FF0000", # 纯红色
"#ADD8E6", # 浅亮蓝色
"#00FF7F", # 明亮的绿色
"#0000CD", # 高饱和度的蓝色
"#FFA07A" # 橙色沙拉
]
plt.figure(figsize=(10, 10))
plt.scatter(digits_pca[:, 0], digits_pca[:, 1], color='none', alpha=0.5)
for i in range(len(digits.data)):
plt.text(digits_pca[i, 0], digits_pca[i, 1], str(digits.target[i]),
color = colors[digits.target[i]], fontdict={'weight':'bold', 'size':9})
plt.xlabel("First principal component")
plt.ylabel("Second principal component")
plt.show()
其绘制的图像为:
3.2 KPCA
然后我们说KPCA,它是当数据为非线性时,即在高维空间中,数据的结构表现出复杂的非线性结构时,而可以去捕捉这些非线性关系的方法。其实,KPCA就是添加一个核函数给PVA后得到的,而这个核函数也是与KSVM(核支持向量机)的核函数类似的。
那么,在这里就不得不说明下核技巧与核函数了。
核技巧(Kernel Trick)
核技巧是一种用于处理高维数据的技术,尤其是在数据难以直接处理时。它允许我们在高维空间中进行计算,而无需显式地将数据映射到这个空间。核技巧的关键在于使用核函数来代替直接在高维空间中的运算。
其核心思想是:在原始数据空间中使用特定的函数来代替高维空间中的内积运算。
原理为:当有数据集X,然后将之映射到更高维度空间F,由非线性映射Φ:X -> F定义,然后对于任意两个数据点与可以用核函数来计算,它在更高维F的内积为,从而不必知道不必知道映射Φ的具体形式或显式计算映射后的数据点。
核函数(Kernel Function)
核函数是一种用于计算两个数据点在高维空间中相似度的函数。它通过映射函数 ϕϕ 将数据点映射到高维空间,并计算它们在该空间中的内积(即相似度)。其形式为:
而常见的核有线性核、多项式核、高斯核与sigmoid核等。
那么接下来就来说明这个核函数是如何运用到PCA中的。
一般在传统的PCA中,步骤有五步,分别为:1.标准化数据;2.计算协方差矩阵;3.求解特征值和特征向量;4.选择主成分;5.映射数据。
但到来KPCA中,我们则有六步,分别为:1.选择核函数;2.构建核矩阵;3.中心化核矩阵,关于中心化处理用如下公式进行:
4.特征值分解;5.选择主成分;6.映射数据,对于一个新的数据点x,在新的主成分空间中表示为:
将上述PCA中的代码修改为KPCA的代码则为如下:
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
from sklearn.decomposition import KernelPCA
from sklearn.preprocessing import StandardScaler
# 加载数据集
digits = load_digits()
# 数据集实例图像
fig, axes = plt.subplots(2, 5, figsize=(10, 5),
subplot_kw={'xticks':(), 'yticks':()})
for ax, img in zip(axes.ravel(), digits.images):
ax.imshow(img)
plt.show()
# 数据预处理(标准化)
scaler = StandardScaler()
digits_scaled = scaler.fit_transform(digits.data)
# KPCA
kpca = KernelPCA(n_components=2, kernel="rbf", gamma=0.1) # 调整gamma参数
kpca.fit(digits_scaled)
digits_kpca = kpca.transform(digits_scaled)
# 绘制降维后的数据
colors = [
"#FF6347", # 热带橙红
"#00BFFF", # 亮青绿色
"#4682B4", # 明亮的蓝宝石色
"#BA55D3", # 亮紫罗兰色
"#FFD700", # 亮金色
"#FF0000", # 纯红色
"#ADD8E6", # 浅亮蓝色
"#00FF7F", # 明亮的绿色
"#0000CD", # 高饱和度的蓝色
"#FFA07A" # 橙色沙拉
]
plt.figure(figsize=(10, 10))
plt.scatter(digits_kpca[:, 0], digits_kpca[:, 1], color='none', alpha=0.5)
for i in range(len(digits_scaled)):
plt.text(digits_kpca[i, 0], digits_kpca[i, 1], str(digits.target[i]),
color = colors[digits.target[i]], fontdict={'weight':'bold', 'size':9})
plt.xlabel("First principal component (KPCA)")
plt.ylabel("Second principal component (KPCA)")
plt.title("KPCA Visualization of Handwritten Digits")
plt.show()
画出的图像也变成了这样:
3.3 LDA
线性判别分析(Linear Discriminant Analysis, LDA)是一种用于分类和降维的技术,尤其适用于多类别分类问题。在降维中,它通过投影将高维数据映射到低维空间,同时保持两类间距最大化和类内距离最大化。
其原理就是:通过线性组合找到一个投影方向,使不同类别的样本在该方向上分离程度最大化,并使同类差异最小化。总的来说,其有四个步骤,分别为:1.计算类间散度矩阵;计算类内散度矩阵;3.求解优化问题;4.投影数据。
我们发现LDA与PCA是由一定相似性的,因为它们都通过线性变换来创建新的特征(主成分或判别函数),但它们在优化目标上不同,PCA是最大化数据在新坐标下的方差,而LDA则是最大化类别间的距离以及最小化类内距离。
在实际使用时,python代码可以是这样的:
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np
data = load_iris()
X = data.data
y = data.target
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 实例化
lda = LinearDiscriminantAnalysis(n_components=2)
# 训练
lda.fit(X_train, y_train)
# 降维
X_train_lda = lda.transform(X_train)
X_test_lda = lda.transform(X_test)
# 输出降维后的数据形状
print("Train set shape after LDA:", X_train_lda.shape)
print("Test set shape after LDA:", X_test_lda.shape)
其输出为:
Train set shape after LDA: (105, 2)
Test set shape after LDA: (45, 2)
3.4 NMF
NMF(Non-negative Matrix Factorization,非负矩阵分解的原理是:对于给定的一个非负矩阵V,NMF去找到两个非负矩阵W和H,使得。其中W矩阵称为基矩阵,H矩阵称为系数矩阵。
如下代码是将一个人脸识别的数据集提取基矩阵并绘图:
import os
import glob
from PIL import Image
import numpy as np
from sklearn.decomposition import NMF
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
# 导入人脸图像
all_path = r"C:\Users\20349\Desktop\ArtificialIntelligence\ML\kaggle\人脸识别数据集"
image_paths = glob.glob(os.path.join(all_path, '*.jpg'))
target_size = (128, 128)
convert_mode = 'RGB'
first_image = Image.open(image_paths[0]).convert(convert_mode)
image_shape = first_image.size
images = []
labels = []
for idx, path in enumerate(image_paths):
img = Image.open(path).convert(convert_mode)
images.append(np.array(img))
labels.append(idx)
image_array = np.array(images)
image_array = image_array.astype('float32') / 255.0
flattened_images = image_array.reshape(image_array.shape[0], -1)
X_train, X_test, y_train, y_test = train_test_split(
flattened_images, labels, test_size=0.2, random_state=42
)
# NMF 处理
nmf = NMF(n_components=15, random_state=42)
nmf.fit(X_train)
X_train_nmf = nmf.transform(X_train)
X_test_nmf = nmf.transform(X_test)
# 可视化
fig, axes = plt.subplots(3, 5, figsize=(15, 12), subplot_kw={'xticks': (), 'yticks': ()})
for i, (component, ax) in enumerate(zip(nmf.components_, axes.ravel())):
ax.plot(component)
ax.set_title(f"{i}.component")
plt.show()
画出的图为:
3.5 FA
因子分析的基本思想是假设观测变量由一些潜在的、不可观测的因子通过线性组合加上一定的随机误差构成。具体来说,假设有 pp 个观测变量 X1,X2,…,Xp,因子分析假设这些变量可以表示为:
其中,X 是一个 p 维的观测变量向量,μ 是一个 p 维的均值向量,L 是一个 p×m 的因子载荷矩阵(factor loading matrix),其中 m<p,F 是一个 m 维的潜在因子向量,ϵ 是一个 p 维的误差向量,通常假定 ϵ 服从独立正态分布,且与 F 不相关。
因子分析可以分为两类,分别为:探索性因子分析与验证性因子分析。
代码如下:
import numpy as np
import pandas as pd
from sklearn.decomposition import FactorAnalysis
import matplotlib.pyplot as plt
# 生成模拟数据
np.random.seed(42)
n_samples = 1000
n_features = 5
X = np.random.randn(n_samples, n_features)
# 应用因子分析
fa = FactorAnalysis(n_components=2)
X_fa = fa.fit_transform(X)
# 可视化结果
plt.figure(figsize=(10, 6))
plt.scatter(X_fa[:, 0], X_fa[:, 1], alpha=0.5)
plt.xlabel("Factor 1")
plt.ylabel("Factor 2")
plt.title("Factor Analysis Result")
plt.show()
最终图像为:
3.6 MDS
多维尺度分析(Multidimensional Scaling, MDS)是一种统计技术,用于可视化高维数据的距离信息或相似度信息。它的主要目的是在低维空间中寻找数据点的位置,使得这些位置之间的距离能够反映原始数据的距离或相似度。
基本原理:MDS是通过某种方式将数据点映射到低维空间,从而在视觉上就可以观察数据点间的关系。
MDS主要分为两类:经典MDS(即Torgerson-Gower MDS)与非度量MDS。前者基于矩阵代数(特别是特征值分解)来解决距离保持问题。而后者更关注于保持数据点之间距离的顺序关系,而不是精确的距离值。经典MDS适用于从原始数据计算得到的相似度矩阵,而非度量MDS则通常用于类别数据或者当原始数据不是直接的距离时使用,它试图保持距离的等级而非绝对数值。
一般来说,MDS有四步,分别为:1.构造矩阵D;2.求中心化距离矩阵B,其中先计算,再求,式子中(表示单位矩阵,表示全为1的n维列向量);3.特征值分解,其中用到式子(U表示特征向量矩阵,λ表示对角线上的特征值矩阵);4.选择主成分,会选择k个最大特征值对应的和,然后计算。
用代码举个例子为:
from sklearn.manifold import MDS
import numpy as np
import matplotlib.pyplot as plt
# 假设我们有一个距离矩阵
distance_matrix = np.array([[0, 1, 2],
[1, 0, 1],
[2, 1, 0]])
# 实例化
mds = MDS(n_components=2, metric=True, max_iter=3000, eps=1e-9, random_state=123,
dissimilarity="precomputed", n_jobs=1)
# 拟合
pos = mds.fit(distance_matrix).embedding_
# 可视化
plt.figure()
plt.scatter(pos[:, 0], pos[:, 1])
for label, x, y in zip(["A", "B", "C"], pos[:, 0], pos[:, 1]):
plt.annotate(label, xy=(x, y), xytext=(-5, 5), textcoords='offset points')
plt.show()
其输出图像为:
最后这个二维的图表就表示之前那个3*3的距离矩阵二维后的大小。
3.7 Isomap
ISOMAP(Isometric Mapping,等距映射)是一种非线性降维技术,它属于流形学习方法之一。这种技术主要用于将高维的数据映射到低维空间中,同时保持数据点之间的相对距离不变。ISOMAP的主要思想是利用数据点之间的最短路径距离(即测地线距离)来构建低维嵌入,从而更好地保留原始数据中的内在几何结构。
其步骤主要为四步:1.临近图构建;最短路径计算(可以用著名的Dijkstra算法或Floyd算法);3.运用MDS算法;4.特征值分解。
我们用三维的“瑞士卷”数据集举例,代码如下:
import numpy as np
from sklearn.datasets import make_swiss_roll
from sklearn.manifold import Isomap
import matplotlib.pyplot as plt
# 生成瑞士卷数据集
X, _ = make_swiss_roll(n_samples=1000, noise=0.05)
# 实例化 ISOMAP 类
isomap = Isomap(n_neighbors=10, n_components=2)
# 拟合并转换数据
X_isomap = isomap.fit_transform(X)
# 可视化结果
plt.figure(figsize=(10, 8))
plt.scatter(X_isomap[:, 0], X_isomap[:, 1], c=X[:, 0], cmap=plt.cm.Spectral)
plt.title("ISOMAP of the Swiss Roll dataset")
plt.colorbar().set_label('z value')
plt.show()
图像如下,我们观察它可以发现其中每个点的颜色反映了原始数据集的位置:
3.8 LLE
LLE(Locally Linear Embedding,局部线性嵌入)是一种用于非线性降维的流形学习方法。LLE 的目标是在低维空间中保持数据点之间的局部关系,即将每个数据点表示为其最近邻点的线性组合。这种方法特别适合处理那些具有非线性结构的数据集。
其步骤有四步:1.构建邻域图;2.计算权重矩阵W;3.构造拉普拉斯矩阵L;4.特征值分解。我们详细看第二三步:首先在计算权重矩阵W时,对于每个数据点找到一组权重,使得可以由其最近邻点通过线性组合得到,而使得。其中,权重通常通过最小化目标函数来确定,这个目标函数为:,同时约束条件为:。然后是第三步的拉普拉斯矩阵L,,I为单位矩阵。
LLE 有几种不同的变种,包括但不限于标准 LLE(Standard LLE)、修改的 LLE(Modified LLE)、Hessian LLE 和 Local Tangent Space Alignment(LTSA)等。
同样,还是用“瑞士卷”数据集来举例子,代码如下:
from sklearn.datasets import make_swiss_roll
from sklearn.manifold import LocallyLinearEmbedding
import matplotlib.pyplot as plt
# 生成瑞士卷数据集
X, _ = make_swiss_roll(n_samples=1000, noise=0.05)
# 实例化 LLE 类
lle = LocallyLinearEmbedding(n_neighbors=10, n_components=2, method='standard')
# 拟合并转换数据
X_lle = lle.fit_transform(X)
# 可视化结果
plt.figure(figsize=(10, 8))
plt.scatter(X_lle[:, 0], X_lle[:, 1], c=X[:, 0], cmap=plt.cm.Spectral)
plt.title("LLE of the Swiss Roll dataset")
plt.colorbar().set_label('z value')
plt.show()
其图像为:
3.9 t-SNE
t-SNE(t-Distributed Stochastic Neighbor Embedding,t-分布随机近邻嵌入)是一种常用的非线性降维技术,主要用于数据可视化。t-SNE 的核心思想是将高维空间中的数据点映射到低维空间(通常是二维或三维),同时保持数据点之间的相似度。具体来说,t-SNE 在高维空间中计算数据点之间的概率分布,在低维空间中计算相应的概率分布,并通过优化低维空间中的布局来最小化这两个分布之间的差异。
其步骤有三步,分别为:1.计算高维空间中的相似度;2.计算低维空间的相似度;3.优化布局。详细看,在第一步中,对于每一个数据点我们计算其与其他数据点间的相似度通常来使用高斯核来计算,而形成一个条件概率,表示数据点是数据点的邻居的概率。而为了确保对称性,需要计算联合概率;然后在计算低维空间的相似度时要用到student分布(即t分布)。
同样,还是用“瑞士卷”数据集来举例子,代码如下:
import numpy as np
from sklearn.datasets import make_swiss_roll
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
# 生成瑞士卷数据集
X, _ = make_swiss_roll(n_samples=1000, noise=0.05)
# 实例化 t-SNE 类
tsne = TSNE(n_components=2, perplexity=30, learning_rate=200, n_iter=1000, random_state=42)
# 拟合并转换数据
X_tsne = tsne.fit_transform(X)
# 可视化结果
plt.figure(figsize=(10, 8))
plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=X[:, 0], cmap=plt.cm.Spectral)
plt.title("t-SNE of the Swiss Roll dataset")
plt.colorbar().set_label('z value')
plt.show()
绘制的图像为:
此上
标签:digits,plt,矩阵,降维,算法,九种,import,数据,sklearn From: https://blog.csdn.net/2301_79096986/article/details/142685923