我们为什么需要减少维度?
高维数据集是具有大量列(或变量)的数据集。这样的数据集带来了许多数学或计算挑战。好消息是变量(或称为特征)通常是相关的 – 高维数据“表面上”被少数简单变量所控制。我们可以找到变量的子集,以表示数据中的相同级别的信息,或将变量转换为新的一组变量,而不会丢失很多信息。虽然高功率计算可以以某种方式处理高维数据,但在许多应用中,仍然需要降低原始数据的维度。
当我们考虑降维时,主成分分析(PCA)可能是最受欢迎的技术。在本文中,我将从 PCA 开始,然后陆续介绍其他维度减少技术。每个技术都会附上 Python 代码。
减少维度也可以找到异常值
数据科学家可以使用降维技术来识别异常。为什么?难道我们只是想减少维度吗?直觉在于异常值本身。D.M.Hawkins 说:“异常值是指观测结果与其他观测结果相差太大,以引起它被不同机制产生的怀疑。”一旦降维到较少的主维度,模式就被识别出来,然后就会显示出异常值。我们可以说异常值检测是降维副的产品,如文章异常检测到 AutoEncoders 易于易于易于修复[1]。
主成分分析(PCA:Principal Component Analysis)
主成分分析(PCA)的概念是减少由大量相关变量组成的数据集的维度,同时保留尽可能多的数据方差。PCA 找到了一组新的变量,即原始变量只是它们的线性组合。新变量称为主成分(PCs)。这些主要成分是正交:在 3-D 情况下,主成分彼此垂直。x 不能由 y 表示,也不能由 z 呈现。
图(a)显示了 PCA 的直觉:它“旋转”轴更好地与您的数据对齐。第一个主成分将捕获数据中的大部分方差,然后后跟第二个,第三等。结果是,新数据将具有更少的维度。
让我们使用鸢尾花数据集来说明 PCA:
# Use the iris dataset to illustrate PCA:
import pandas as pd
url = “https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# load dataset into Pandas DataFrame
df = pd.read_csv(url, names=['sepal length','sepal width','petal length','petal width','target'])
df.head()

请注意,此 Iris 数据集附带目标变量。在 PCA 中,您只能在没有目标 Y 变量的情况下转换 x 变量。
标准化:所有变量应在应用 PCA 之前应在相同的比例上,否则,具有大值的特征将主导结果。这一点进一步解释了我的帖子避免这些致命建模错误,可能会浪费你职业生涯[2]。下面我使用scikit-standardscaler – 学习将数据集的特征标准化到单位刻度上(平均值= 0 和方差= 1)。
from sklearn.preprocessing import StandardScaler
variables = ['sepal length', 'sepal width', 'petal length', 'petal width']
x = df.loc[:, variables].values
y = df.loc[:,['target']].values
x = StandardScaler().fit_transform(x)
x = pd.DataFrame(x)

原始数据中有四个特征。所以 PCA 将提供相同数量的主成分。
from sklearn.decomposition import PCA
pca = PCA()
x_pca = pca.fit_transform(x)
x_pca = pd.DataFrame(x_pca)
x_pca.head()

每个主成分解释的差异是什么?使用pca.explate_variance_ratio_
返回方差的向量:
explained_variance = pca.explained_variance_ratio_
explained_variance
它显示了第一个主要成分占 72.22%的差异,第二个,第三和第四个占 23.9%,3.68%和 0.51%的差异。我们可以说 72.22 + 23.9 = 96.21%的信息由第一和第二主成分捕获。我们经常希望只保留重要的特征并放弃微不足道的特征。拇指(经验)规则
保持顶部的主成分,捕捉重要的方差和忽视小的。
我们可以使用前两个组件绘制结果。让我们将目标变量 y 附加到新数据 x_pca:
x_pca['target']=y
x_pca.columns = ['PC1','PC2','PC3','PC4','target']
x_pca.head()
结果显示数据在新空间中可分离。
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlabel('Principal Component 1')
ax.set_ylabel('Principal Component 2')
ax.set_title('2 component PCA')
targets = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
colors = ['r', 'g', 'b']
for target, color in zip(targets,colors):
indicesToKeep = x_pca['target'] == target
ax.scatter(x_pca.loc[indicesToKeep, 'PC1']
, x_pca.loc[indicesToKeep, 'PC2']
, c = color
, s = 50)
ax.legend(targets)
ax.grid()

KPCA(Kernel PCA)
PCA 仅适用于线性变换。而KPCA支持非线性变换。首先将原始数据映射到某些非线性特征空间(通常更高的维度),然后应用 PCA 以提取该空间中的主成分。这可以通过图(b)来理解。左侧的图形显示了使用任何线性变换不能分离蓝色和红色点。但是,如果所有点都投射到 3D 空间上,则结果变得线性可分离!然后,我们将 PCA 应用于分离成分。
直觉来自哪里?为什么分离在高维空间中更容易变得更容易?这必须返回 Vapnik-Chervonenkis(VC)理论。它将映射到更高的维度空间通常提供更大的分类效果。
以下 Python 代码使由红色和蓝色点组成的圆形曲线。显然,没有办法将红色和蓝色点用一条直线分离(线性分离)。
print(__doc__)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA, KernelPCA
from sklearn.datasets import make_circles
np.random.seed(0)
X, y = make_circles(n_samples=400, factor=.3, noise=.05)
plt.figure(figsize=(10,10))
plt.subplot(2, 2, 1, aspect='equal')
plt.title("Original space")
reds = y == 0
blues = y == 1
plt.scatter(X[reds, 0], X[reds, 1], c="red",s=20, edgecolor='k')
plt.scatter(X[blues, 0], X[blues, 1], c="blue",s=20, edgecolor='k')
plt.xlabel("$x_1$")
plt.ylabel("$x_2$")
但是,当我们将圆圈投射到更高的维度空间并使用 PCA 分开时,针对第一和第二主成分的数据观察是可分离的!以下结果是针对第一和第二主成分绘制点的结果。我画一条线来分隔红色和蓝色点。在 KernelPCA 中,我们指定内核=’RBF’,即径向基函数[3],或 euclidean 距离。RBFS 通常用作机器学习技术中的内核,例如支持向量机(SVM)[4]。
kpca = KernelPCA(kernel="rbf", fit_inverse_transform=True, gamma=10)
X_kpca = kpca.fit_transform(X)
pca = PCA()
X_pca = pca.fit_transform(X)
plt.scatter(X_kpca[reds, 0], X_kpca[reds, 1], c="red",s=20, edgecolor='k')
plt.scatter(X_kpca[blues, 0], X_kpca[blues, 1], c="blue",s=20, edgecolor='k')
x = np.linspace(-1, 1, 1000)
plt.plot(x, -0.1*x, linestyle='solid')
plt.title("Projection by KPCA")
plt.xlabel(r"1st principal component in space induced by $phi$")
plt.ylabel("2nd component")
如果我们将内核指定为“线性”, 如下面的代码(KernelPCA(kernel="linear")
),则成为只有线性变换的标准 PCA,红色和蓝色点不可分离。
kpca = KernelPCA(kernel="linear", fit_inverse_transform=True, gamma=10)
X_kpca = kpca.fit_transform(X)
pca = PCA()
X_pca = pca.fit_transform(X)
plt.scatter(X_kpca[reds, 0], X_kpca[reds, 1], c="red",s=20, edgecolor='k')
plt.scatter(X_kpca[blues, 0], X_kpca[blues, 1], c="blue",s=20, edgecolor='k')
x = np.linspace(-1, 1, 1000)
plt.plot(x, -0.1*x, linestyle='solid')
plt.title("Projection by KPCA")
plt.xlabel(r"1st principal component in space induced by $phi$")
plt.ylabel("2nd component")
线性判别分析(LDA:Linear Discriminant Analysis)
LDA 的起源与 PCA 不同。PCA 是一种无监督的学习方法,将原始特征转换为一组新特征。我们不关心新的一组特征是否可以为目标变量提供最佳的区分能力。相比之下,线性判别分析(LDA)寻求保持与所属变量尽可能多的辨别力,同时将原始数据矩阵突出到较低维空间上。LDA 是一种有监督学习技术的类型。它利用从属变量中的类将预测器的空间划分为区域。所有区域应该有线性边界。这就是名称中线性由来。该模型预测,区域内的所有观察属于来自相关变量的相同类别。
LDA 通过三个主要步骤中实现了上述目标。
-
首先,它计算从属变量的不同类别之间的可分离性,称为级别方差,如(1)所示。 -
其次,它计算每个类的平均值和样本之间的距离,该距离被称为级别方差,如(2)所示。 -
最后,它通过此标准构造了较低维度的空间:最大化类别之间的方差并最小化类别内方差。该标准的解决方案是计算特征值和特征向量。得到的特征向量代表了新空间的方向,相应的特征值代表了特征向量的长度。因此,每个特征向量代表 LDA 空间的一个轴,并且特征值代表该特征向量的长度。
我将使用在 Kaggle 中的数据集红葡萄酒质量[5],此数据集具有 11 个输入变量和一个输出变量quality
。
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
wine = pd.read_csv('winequality-red.csv')
wine.head()
为了简单起见,我将输出变量重新组建为三个值,
wine['quality2'] = np.where(wine['quality']<=4,1, np.where(wine['quality']<=6,2,3))
以下代码执行 PCA 和 LDA。
X = wine.drop(columns=['quality','quality2'])
y = wine['quality2']
target_names = np.unique(y)
target_names
pca = PCA(n_components=2)
X_r = pca.fit(X).transform(X)
lda = LinearDiscriminantAnalysis(n_components=2)
X_r2 = lda.fit(X, y).transform(X)
然后绘制 PCA 和 LDA 的结果:
# Percentage of variance explained for each components
print('explained variance ratio (first two components): %s'
% str(pca.explained_variance_ratio_))
plt.figure()
colors = ['navy', 'turquoise', 'darkorange']
lw = 2
for color, i, target_name in zip(colors, target_names, target_names):
plt.scatter(X_r[y == i, 0], X_r[y == i, 1], color=color, alpha=.8, lw=lw,
label=target_name)
plt.legend(loc='best', shadow=False, scatterpoints=1)
plt.title('PCA of WINE dataset')
plt.figure()
for color, i, target_name in zip(colors, target_names, 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 of WINE dataset')
plt.show()
奇异值分解(SVD:Singular Value Decomposition)
SVD 是类似于 PCA 的数据摘要方法。它从数据中提取重要特征。但 SVD 还有一个优势:将原始数据集重建为小型数据集。所以它具有广泛的应用,如图像压缩等。例如,如果您有32*32=1024
像素图像,则 SVD 可以将其概括为 66 像素。66 像素可以检索32*32
像素图像而不会错过任何重要信息。
SVD 在线性代数中发挥了重要作用,但在吉尔伯特·斯特朗(Gilbert Strang)的经典教科书《线性代数及其应用》(linear algebra and Its Applications)中,它似乎“不像它应该的那样出名”。为了正确地引入奇异值分解,必须从矩阵运算开始。如果 A 是对称实n*n
矩阵,则存在一个正交矩阵V
和一个对角矩阵D

列V
是 A 的特征向量,D
的对角线条目是 A 的特征值。该过程称为矩阵a
的特征值分解
,或EVD
。它告诉我们如何选择 Orthonormal 基础,以便转换由具有最简单形式的矩阵表示,即对角线。(对于想要越过步骤的读者来对角度化矩阵,这里[6]是一个很好的示例。)术语正式意味着两个载体是正交或垂直的。
列V
是 A 的特征向量,D
的对角项是 A 的特征值。这个过程称为矩阵A
的特征值分解,或EVD
。它告诉我们如何选择标准正交
基底,这样变换就可以用一个矩阵来表示它的最简单形式,也就是对角线形式。(对于想要了解矩阵对角化步骤的读者,可以参考这里[7]。
扩展对称矩阵,SVD 适用于任意实数mxn
矩阵A*
。给定一个实数m×n
矩阵a
,存在一个正交的m×m
矩阵 U,一个正交m×m
矩阵 V,一个对角的m×n
矩阵 Σ,

注意,一个正交矩阵是一个方阵,其自身及其逆矩阵的乘积是单位矩阵。对角线矩阵是指除对角线以外的所有元素都为零的矩阵。
下面我将再次使用鸢尾花数据集向您展示如何应用 SVD。
from numpy import *
import operator
import matplotlib.pyplot as plt
import pandas as pd
from numpy.linalg import *
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
# load dataset into Pandas DataFrame
df = pd.read_csv(url, names=['sepal length','sepal width','petal length','petal width','target'])
# Only the X variables
data = df[['sepal length','sepal width','petal length','petal width']]
#calculate SVD
n = 2 # We will take two Singular Values
U, s, V = linalg.svd( data )
# eye() creates a matrix with ones on the diagonal and zeros elsewhere
Sig = mat(eye(n)*s[:n])
newdata = U[:,:n]
newdata = pd.DataFrame(newdata)
newdata.columns=['SVD1','SVD2']
newdata.head()

您可以将 SVD 的结果与 PCA 的结果进行比较。两者都达到了类似的结果。
# Add the actual target to the data in order to plot it
newdata['target']=df['target']
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlabel('SVD 1')
ax.set_ylabel('SVD 2')
ax.set_title('SVD')
targets = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
colors = ['r', 'g', 'b']
for target, color in zip(targets,colors):
indicesToKeep = newdata['target'] == target
ax.scatter(newdata.loc[indicesToKeep, 'SVD1']
, newdata.loc[indicesToKeep, 'SVD2']
, c = color
, s = 50)
ax.legend(targets)
ax.grid()

t 分布-随机邻近嵌入(t-SNE:t-distributed Stochastic Neighbor Embedding)
t-SNE 由Laurens Van der Maaten 和 Geoggrey Hinton[8]开发的。它是一种用于可视化的机器学习算法,其呈现在两或三维的低维空间中嵌入高维数据。
将上述三维瑞士卷呈现为二维的最佳方式是什么?直观地我们希望“展开”瑞士卷到一个平坦的蛋糕。在数学中,它意味着类似的观点将成为附近的点,异常点将成为距离点。
图(C)显示了另一个例子。它是一个三维四面体,数据点聚类在顶点。如果我们只是像 Panel (a)那样将三维图折叠成二维图,它就不能很好地工作,因为组(a)变成了中心集群。相比之下,Panel (B)可能是一个更好的 2d 展示,它保留了 Cluster (a)-(E)之间的距离,同时保留了每个 Cluster 中点的局部距离。t-SNE 是一种非线性降维技术,用于保持局部邻域。如果一组点在 t-SNE 图上聚在一起,我们可以相当肯定这些点彼此很接近。
t-SNE 对点之间的相似性进行建模。它是如何定义相似性的?首先,它是由点Xi和Xj之间的欧氏距离定义的。其次,定义为“数据点i与点j的相似度是点i根据高斯分布下的概率选择其他邻居时,将数据点j作为其邻居的条件概率p”的条件概率。在下面的条件表达式中,如果点j比其他点更接近点i,那么它被选中的概率就更高(注意负号)。

t-SNE 的目标是通过点Yi和Yj之间的低维空间q来匹配上述j和i的条件概率p,如下图所示。概率q遵循长尾 Student-t 分布,这就是 t-SNE 中的T的由来。

下一步是找到Yi,使得分布q尽可能接近分配p。t-SNE 使用梯度下降技术,一种寻找值的优化技术。
下面我展示了如何与鸢尾花数据集一起使用 t-SNE 技术。
from sklearn.manifold import TSNE
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
iris = load_iris()
X_tsne = TSNE(learning_rate=100).fit_transform(iris.data)
X_pca = PCA().fit_transform(iris.data)
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=iris.target)
plt.subplot(122)
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target)
有关 t-SNE 更多信息,这篇文章“如何更有效地使用 t-SNE[9]”提供了更多的讨论。
参考资料
异常检测到 AutoEncoders 易于易于易于修复: https://towardsdatascience.com/anomaly-detection-with-autoencoder-b4cdce4866a6
[2]
避免这些致命建模错误,可能会浪费你职业生涯: https://towardsdatascience.com/avoid-these-deadly-modeling-mistakes-that-may-cost-you-a-career-b9b686d89f2c
[3]
径向基函数: https://en.wikipedia.org/wiki/radial_basis_function
[4]
支持向量机(SVM): https://en.wikipedia.org/wiki/support-vector_machine
[5]
红葡萄酒质量: https://www.kaggle.com/piyushgeyal443/red-wine-dataset#winequalityInfo.txt
[6]
这里: https://yutsumura.com/how-to-diagonalize-a-matrix-step-by-step-explanonation/
[7]
这里: https://yutsumura.com/how-to-diagonalize-a-matrix-step-by-step-explanation/
[8]
Laurens Van der Maaten 和 Geoggrey Hinton: http://www.cs.toronto.edu/~hinton/absps/tsne.pdf
[9]
如何更有效地使用 t-SNE: https://distill.pub/2016/misread-tsne/
原文:Dimension Reduction Techniques with Python
链接:https://towardsdatascience.com/dimension-reduction-techniques-with-python-f36ca7009e5c?gi=836dd28c32df
作者:Dr. Dataman
原文始发于微信公众号(alitrack):基于 Python 的降维技术实战
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/62877.html