无监督学习与生成式人工智能(MEAP)(一)(4)https://developer.aliyun.com/article/1522506
3.6 奇异值分解(SVD)
在上一节中,我们学习了主成分分析(PCA)。PCA 线性地转换数据并生成彼此不相关的主成分。但是特征值分解的过程只能应用于方阵。而奇异值分解(SVD)可以应用于任何 m x n 矩阵。我们现在将更详细地学习这一点。
让我们考虑我们有一个矩阵 A。A 的形状是 m x n,或者包含 m 行和 n 列。A 的转置可以表示为 A^T。
我们可以使用 A 和 A^T 创建另外两个矩阵作为A A^T 和A^TA。这些结果矩阵A A^T 和A^TA具有一些特殊的性质,这些特性如下所列。这些性质的数学证明超出了本书的范围。
A A^T 和 A^TA 的性质是:
- 它们都是对称的方阵。
- 它们的特征值要么是正的,要么是零。
- A A^T 和 A^TA(带上▲)具有相同的特征值。
- A A^T 和 A^TA 的秩与原矩阵 A 相同。
A A^T 和 A^TA 的特征向量分别被称为 A 的奇异向量。它们的特征值的平方根被称为奇异值。
由于这两个矩阵(A A^T 和 A^TA)都是对称的,它们的特征向量互相正交。换句话说,由于是对称的,特征向量是相互垂直的,并且可以具有单位长度。
现在,有了这种数学理解,我们可以定义 SVD。根据奇异值分解方法,可以将任何矩阵 A 分解为
(公式 3.3)
A = U * S * V^T
在这里,A 是原始矩阵,
U 和 V 是正交矩阵,它们的正交特征向量来自于 A A^T 或 A^TA,分别是
S 是对角矩阵,其 r 个元素等于奇异值。
简单地说,SVD 可以被视为使用特征值分解对 PCA 方法进行增强。
奇异值分解比特征值分解更好,且在数值上更健壮。
PCA 被定义为使用主成分对输入变量进行线性转换。所有线性转换、选择最佳成分等概念都保持相同。主要的过程步骤保持相似,除了在 SVD 中,我们使用了稍微不同的方法,其中特征值分解被替换为使用奇异向量和奇异值。通常建议在数据集稀疏时使用 SVD,在数据集较密集时使用 PCA。
小测验——回答这些问题以检查您的理解力。本书末尾将给出答案。
- SVD 基于特征值分解技术。是真还是假?
- PCA 比 SVD 更具鲁棒性。是真还是假?
- SVD 中奇异值和奇异向量是什么?
接下来,在下一节中,我们将使用 SVD 创建一个 Python 解决方案。
3.6.1 使用 SVD 的 Python 解决方案。
在此案例研究中,我们使用的是“蘑菇”数据集。该数据集包含 23 个烤蘑菇物种的描述。有两个类别——蘑菇是可食用的,“e”,否则蘑菇是有毒的,“p”。
步骤 1: 导入库。我们正在导入
import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from sklearn.preprocessing import LabelEncoder, StandardScaler
步骤 2: 导入数据集并检查形状、头等。
mushrooms_df = pd.read_csv('mushrooms.csv') mushrooms_df.shape mushrooms_df.head()
步骤 3: 我们可以观察到,数据集中的值是分类的。它们必须首先被编码为数字值。这不是处理分类变量的唯一方法。本书的最后一章将探讨其他技术。我们将深入探索这些技术。
首先,我们调用 LabelEncoder,然后将其应用到数据集中的所有列。LabelEncoder 使用一种独热编码方法将分类变量转换为数字变量。
encoder = LabelEncoder() for col in mushrooms_df.columns: mushrooms_df[col] = encoder.fit_transform(mushrooms_df[col])
步骤 4: 重新查看数据集。所有分类值都已转换为数字值。
mushrooms_df.head()
第 5 步: 接下来的两步与上一个案例研究相同,在这两步中,我们将数据集分解为 X 变量和 y 标签。然后对数据集进行标准化。
X_variables = mushrooms_df.iloc[:,1:23] y_label = mushrooms_df.iloc[:, 0] scaler = StandardScaler() X_features = scaler.fit_transform(X_variables)
第 6 步: 在这一步中,我们实现了 SVD。在 numpy 中有一个实现 SVD 的方法。输出是 u、s 和 v,其中 u 和 v 是奇异向量,s 是奇异值。如果您愿意,您可以分析它们各自的形状和维度。
u, s, v = np.linalg.svd(X_features, full_matrices=True)
第 7 步: 我们知道奇异值允许我们计算每个奇异向量解释的方差。我们现在将分析每个奇异向量解释的%方差,并绘制出来。结果显示到小数点后三位。然后我们将结果绘制成直方图。在 x 轴上是奇异向量,而在 y 轴上是%解释的方差。
variance_explained = np.round(s**2/np.sum(s**2), decimals=3) variance_explained sns.barplot(x=list(range(1,len(variance_explained)+1)), y=variance_explained, color="blue") plt.xlabel('SVs', fontsize=16) plt.ylabel('Percent of the variance explained', fontsize=15)
第 8 步: 现在我们将创建一个数据框。这个新的数据框 svd_df 包含了前两个奇异向量和元数据。然后我们使用 head 命令打印前 5 行。
col_labels= ['SV'+str(i) for i in range(1,3)] svd_df = pd.DataFrame(u[:,0:2], index=mushrooms_df["class"].tolist(), columns=col_labels) svd_df=svd_df.reset_index() svd_df.rename(columns={'index':'Class'}, inplace=True) svd_df.head()
第 9 步: 与上一案例类似,我们将数值替换为实际的类标签。1 代表可食用,而 0 代表有毒。
svd_df['Class'] = svd_df['Class'].replace({1:'Edible', 0:'Poison'})
第 10 步: 我们现在正在绘制两个组件解释的方差。这里我们只选择了前两个组件。建议您使用上一节描述的方法选择最佳的组件数量,并绘制相应的散点图。在这里,x 轴上显示了第一个奇异向量 SV1,而 y 轴上显示了第二个奇异向量 SV2。
color_dict = dict({'Edible':'Black', 'Poison': 'Red'}) sns.scatterplot(x="SV1", y="SV2", hue="Class", palette=color_dict, data=svd_df, s=105, alpha=0.5) plt.xlabel('SV 1: {0}%'.format(variance_explained[0]*100), fontsize=15) plt.ylabel('SV 2: {0}%'.format(variance_explained[1]*100), fontsize=15)
我们可以观察两个类别相对于两个组件的分布情况。两个类别 - 可食用和有毒 - 被分别以黑色和红色编码。正如我们上面所指出的,我们只选择了两个组件来展示使用可视化图的影响。建议您使用上一个案例研究中描述的方法选择最佳的组件数量,然后使用不同的奇异向量来可视化结果。这个解决方案可以用来在实际数据集中减少维度。
这就结束了我们对 SVD 的讨论。我们将在下一节中观察 PCA 和 SVD 的优势和挑战。
3.7 维度缩减的优缺点
在本章的开头部分,我们讨论了维度诅咒的缺点。在最后几节中,我们了解了 PCA 和 SVD,并使用 Python 进行了实现。在当前部分,我们将审查这些技术的优势和挑战。
实施 PCA 或 SVD 时我们获得的主要优势如下:
- 降低维度会减少数据集的复杂性。相关特征被移除并进行了转换。手动处理相关变量是一项相当手动和令人沮丧的工作。PCA 和 SVD 等技术可以很容易地帮助我们完成这项工作。相关特征的数量被最小化,并且整体维度被降低。
- 如果维度较少,数据集的可视化效果会更好。极高维度的数据集很难进行可视化。
- 如果移除相关变量,机器学习模型的准确性会得到改善。这些变量不会对模型的性能有所贡献。
- 训练时间减少因为数据集的复杂性较低。因此,需要较少的计算力和时间。
- 在监督机器学习模型中,过拟合是一个讨厌的问题。这是一种情况,模型在训练数据集上表现良好,但在测试/验证数据集上却表现不佳。这意味着模型可能无法在真实世界的未知数据集上表现良好。而这违背了构建机器学习模型的整个目的。PCA/SVD 通过减少变量数量来帮助解决过拟合问题。
与此同时,我们在降维技术中面临一些挑战,如下所述:
- PCA/SVD 创建的新组件不太可解释。它们是数据集中独立变量的组合,实际上与真实世界没有关系,因此很难将它们与真实世界的情况联系起来。
- PCA/SVD 需要数值变量。因此,所有分类变量必须以数值形式表示。
- 在实施解决方案之前,需要对数据集进行归一化/标准化。
- 当使用 PCA 或 SVD 时可能会发生信息损失。主成分无法取代原始数据集,因此在实施这些方法时可能会有一些信息损失。
但尽管存在一些挑战,PCA 和 SVD 用于降低数据集的维度。它们是最受欢迎的方法之一,也被广泛使用。与此同时,必须注意的是,这些都是线性方法,我们将在本书的后期部分介绍非线性方法。
通过这样,我们已经涵盖了在降维中使用的两种重要技术。我们将在后面的章节中探讨更高级的技术。是时候转到案例研究了,这是本章的下一部分内容。
3.8 降维案例研究
现在我们将探索一个真实案例,以了解 PCA 和 SVD 在真实商业场景中的使用。
想象一下:你正在为一个电信服务提供商工作。你有一个订户基础,并希望根据许多参数对消费者进行聚类。但挑战在于需要分析的庞大维度。
目标是使用降维算法减少属性的数量。消费者数据集可以如下所示。
- 订户的人口统计详情将包括年龄、性别、职业、家庭规模、婚姻状况等。下面显示的列表并不全面。
表格 3.4 订户的人口统计详情,如年龄、性别、婚姻状况、家庭规模、城市等。
- 消费者的订阅详情可能如下表所示。下面显示的列表并不全面。
表格 3.5 订户的订阅详情,如服务期限、预付费/后付费连接等。
- 消费者的使用情况将描述分钟数、通话费率、数据使用情况、服务等。下面显示的列表并不全面。
表格 3.6 订户的使用情况指定了使用的分钟数、发送的短信、使用的数据、在网络中度过的天数、国内或国际使用情况等。
- 订户的付款和交易详情将涉及到所做的各种交易、付款方式、付款频率、自上次付款以来的天数等。
表格 3.7 展示了订户的交易详情,包括金额、模式等的所有详情。
数据集可能有更多属性。到目前为止,我们已经确定所涉及的变量数量确实很高。一旦我们汇总了所有这些数据点,最终数据的维数就可能非常庞大。
表格 3.8 最终数据集是所有上述数据集的组合。这将是一个庞大的、真正高维的数据集,需要进行分析。
在我们能够进行任何监督或无监督解决方案之前,我们必须减少属性的数量。在本章中,我们专注于降维技术,因此步骤涵盖了该过程的这一方面。在后面的章节中,我们将更详细地研究探索性分析。
作为第一步,我们将对数据集进行健全性检查并进行数据清理。我们将检查数据点的数量,缺失值的数量,重复值,存在的垃圾值等。这将使我们能够删除可能非常稀疏或包含不多信息的任何变量。例如,如果性别仅适用于客户基数的 0.01%,则去除该变量可能是个不错的主意。或者如果所有客户的性别都为男性,该变量对我们没有添加任何新信息,因此可以丢弃。有时,使用业务逻辑,可能会从数据集中删除一个变量。在前面的部分中已经讨论了一个例子。在这一步骤中,我们可能会组合一些变量。例如,我们可能通过将总支出金额除以总交易数来创建一个新变量作为平均交易值。以这种方式,我们将能够减少一些维度。
一个 Python Jupyter 笔记本可在 Github 存储库中找到,我们在那里提供了对数据清理步骤的非常详细的解决方案。
基本数据清洗完成后,我们开始进行探索性数据分析。作为探索性分析的一部分,我们检查变量的分布、其分布情况,数值变量的平均数/中位数/众数。这有时被称为单变量分析。这一步骤允许我们测量变量的分散程度,了解中心趋势,检查分类变量的不同类别的分布,并查找值中的任何异常情况。例如,使用上述提到的数据集,我们将有兴趣分析数据使用的最高/最低/平均值,或者性别或年龄的%分布。我们想知道最受欢迎的交易方式,我们也对交易的最高/最低/平均金额感兴趣。等等,这个列表还可以继续下去。
然后我们探索变量之间的关系,这被称为双变量分析。交叉表,数据分布是双变量分析的一部分。在这一步骤, 创建了一个相关矩阵。需要仔细研究高度相关的变量。根据业务逻辑, 其中一个变量可能会被丢弃。这一步骤有助于可视化和理解一个变量在其他变量存在的情况下的行为。我们可以检查它们的相互关系和关系的强度。在本案例研究中, 我们将回答诸如 - 对比使用更多数据的订阅者与发送更多短信的订阅者, 是否在网络上花费更多时间。或假设 - 使用在线模式进行交易的订阅者是否比使用现金进行交易的订阅者产生更多收入。或者性别/年龄与数据使用之间是否存在关系。在项目的这个阶段, 将回答许多这样的问题。
Github 存储库中提供了 Python Jupyter 笔记本,提供了单变量和双变量阶段的详细步骤和代码。来看一下吧!
在此阶段,我们拥有一个具有大量维度的数据集,并希望减少维数。现在是实施 PCA 或 SVD 的好时机。这些技术将减少维数,并使数据集准备好在过程的下一步中使用,如图 3.8 所示。这张图仅是一个代表性的结构,用于描述维数约简方法的影响。请注意,左图中的大量黑线正在缩减为右图中较少的红线。
图 3.8 非常高维的数据集将通过捕获数据集中的最大方差来减少到低维度
降维方法的输出将是一个少于原始变量数量的数据集。该数据集可以用于监督学习或无监督学习。我们已经在本章前面的章节中介绍了使用 Python 的例子。
这结束了我们关于电信用户的案例研究。这种情况可以扩展到其他领域,如零售、银行金融、航空、医疗保健、制造等。
现在我们将进入本章的总结。
3.9 总结
数据无处不在,以各种形式、层次、维度呈现,具有不同的复杂程度。人们经常提到“数据越多越好”。在一定程度上这确实是正确的。但是,如果维度非常高,从中获取有用信息将会非常困难。数据分析可能会出现偏差,并且处理起来非常复杂。我们在本章探讨了维数灾难。PCA / SVD 可以帮助减少这种复杂性。他们使数据集准备好下一步。
但是维数约简并不像看起来那么简单。这不是一个容易完成的任务。但它确实是一个非常有回报的任务。并需要商业眼光、逻辑和常识的结合来处理。结果数据集可能仍需要一些额外的工作。但这是建立机器学习模型的一个很好的起点。
这标志着第三章的结束。同时也结束了本书的第一部分。在本部分中,我们介绍了更基础的算法。我们从本书的第一章开始探究机器学习的基础和基本知识。在第二章中,我们探讨了三个聚类算法。在第三章中,我们探索了 PCA 和 SVD。
在书的第二部分,我们正在转向并学习更先进的话题。我们将在下一章开始研究关联规则。然后我们进入高级聚类方法,比如时间序列聚类、模糊聚类、GMM 聚类等等。接着是一章关于高级的降维算法,比如 t-SNE、LDA。然后,在第二部分的结束,我们将研究无监督学习在文本数据集上的应用。书的第三部分更加先进,我们将深入基于神经网络的解决方案并使用图像数据集。所以还有很长的路要走!敬请关注!
现在你可以进入问题部分了!
实际的下一步和建议的阅读
- 使用上一章节使用的车辆数据集进行聚类,并在其上实施 PCA 和 SVD。比较在实施 PCA 和 SVD 之前和之后进行聚类的性能。
- 从 (
data.world/datasets/pca
) 获取数据集。在这里,你会发现许多数据集,比如联邦计划网络安全、比萨数据集等等。比较在这些数据集上实施 PCA 和 SVD 的性能。 - 阅读下面关于主成分分析(PCA)的论文
www.sciencedirect.com/science/article/pii/009830049390090R
web.stanford.edu/~hastie/Papers/spc_jcgs.pdf
web.cs.ucdavis.edu/~vemuri/papers/pcaVisualization.pdf
cseweb.ucsd.edu/~ravir/papers/pca/pamifinal.pdf
- 阅读一下关于奇异值分解的研究论文
people.maths.ox.ac.uk/porterm/papers/s4.pdf
papers.nips.cc/paper/3473-quic-svd-fast-svd-using-cosine-trees.pdf
arxiv.org/pdf/1211.7102.pdf
glaros.dtc.umn.edu/gkhome/fetch/papers/sarwar_SVD.pdf
3.10 总结
- 我们了解到,在数据集中拥有很多维度会引发一个问题,即维度灾难。由于维度灾难的存在,数据集变得非常复杂,处理起来也变得更加耗时。
- 我们还提到了可以有多种技术来解决维度灾难的问题,比如 PCA、LDA、SVD、自编码器、t-SNE、等等。
- 我们详细介绍了主成分分析(PCA),在其中我们学到,一个主成分是各种变量的线性组合。使用这种方法,通过具有捕捉数据集中最大方差的主成分,可以减少总维数。
- 然后我们转向奇异值分解,在这一部分,大部分过程与 PCA 相同,只是 PCA 中的特征值分解被奇异向量和奇异值在 SVD 中替换了。
- 我们还学到,当得到主成分后,虽然解决了维度灾难的问题,但原始变量却丢失了。
- 最后,我们使用 sklearn 库对这些技术进行了 Python 实现。