奇异值分解简介:从原理到基础机器学习应用

2024-06-17 16:32

本文主要是介绍奇异值分解简介:从原理到基础机器学习应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


矩阵分解在机器学习应用中的重要性无需多言。本文对适用范围很广的奇异值分解方法进行了介绍,并通过代码演示说明了其工作方式、计算方法及其常见的几种基础应用。

矩阵分解也叫矩阵因子分解,涉及到用给定矩阵的组成元素描述该矩阵。

奇异值分解(SVD)可能是最著名和使用最广泛的矩阵分解方法。所有矩阵都有一种 SVD 方法,这使得其比特征分解(eigendecomposition)等其它方法更加稳定。因此,这种方法在很多应用中都有应用,包括压缩、去噪、数据压缩。

在这份教程中,你将了解用于将矩阵分解成其组成元素的奇异值分解方法。

在完成本教程后,你将了解:

  • 奇异值分解是什么以及涉及什么

  • 如何计算 SVD 以及如何根据 SVD 元素重建矩形和方形矩阵

  • 如何使用 SVD 计算伪逆和执行降维

那就开始吧!

教程概览

本教程分为 5 部分,依次为:

1. 奇异值分解

2. 计算奇异值分解

3. 根据 SVD 重建矩阵

4. 用于伪逆的 SVD

5. 用于降维的 SVD

奇异值分解

奇异值分解(SVD)是一种用于将矩阵归约成其组成部分的矩阵分解方法,以使后面的某些矩阵计算更简单。

为了说明简单,我们将关注用于实数值矩阵的 SVD,而会忽略复数矩阵的情况。

其中 A 是我们希望分解的 n×m 的实矩阵,U 是一个 m×m 矩阵,Sigma(通常用大写的希腊字母 ∑表示)是一个 m×n 的对角矩阵,V^T 是一个 n×n 矩阵的转置,其中 T 是上标。奇异值分解是线性代数的一个亮点。

——《Introduction to Linear Algebra》第五版,2016 年,第 371 页

Sigma 矩阵中的对角值被称为原始矩阵 A 的奇异值。U 矩阵的列被称为 A 的左奇异向量,V 的列被称为 A 的右奇异向量。

SVD 是通过迭代式的数值方法计算的。我不会详细深入这些方法的细节。每一个矩形矩阵都有一个奇异值分解,尽管所得到的矩阵可能包含复数值以及浮点算术的局限性可能会导致某些矩阵无法简单利落地完成分解。 

奇异值分解(SVD)提供了另一种将矩阵分解成奇异向量和奇异值的方式。SVD 让我们可以发现某些与特征分解同种类型的信息。但是,SVD 有更广的适用性。

——《Deep Learning》,2016 年,第 44-45 

SVD 在矩阵求逆等其它矩阵运算的计算有广泛的应用,但也可用作机器学习中的数据归约方法。SVD 也可用在最小二乘线性回归、图像压缩和数据去噪中。

奇异值分解(SVD)在统计学、机器学习和计算机科学领域有很多应用。将 SVD 应用于矩阵就像是使用 X 射线进行透视……

——《No Bullshit Guide To Linear Algebra》,2017 年,第 297 页

计算奇异值分解

SVD 可以通过调用 svd() 函数进行计算。

该函数在处理矩阵后会返回 U、Sigma 和 V^T 元素。Sigma 对角矩阵是按奇异值向量的形式返回的。V 矩阵是以转置后的形式返回的,比如 V.T.

下面的示例定义了一个 3×2 矩阵并计算了奇异值分解。

运行这个示例,首先会显示定义的 3×2 矩阵,然后会显示分解计算得到的 3×3 的 U 矩阵、2 个元素的 Sigma 向量和 2×3 的 V^T 矩阵元素。

根据 SVD 重建矩阵

原始矩阵可以根据 U、Sigma 和 V^T 元素重建出来。

svd() 返回的 U、s 和 V 元素不能直接相乘。 

s 向量必须使用 diag() 函数转换成对角矩阵。默认情况下,这个函数将创建一个相对于原来矩阵的 m×m 的方形矩阵。这是有问题的,因为该矩阵的尺寸并不符合矩阵乘法的规则,即一个矩阵的列数必须等于后一个矩阵的行数。

在创建了方形的 Sigma 对角矩阵之后,各个矩阵的大小与我们分解的原始 n×m 矩阵是相关的,如下:

而事实上我们需要:

我们可以通过创建一个全是 0 值的 m×n 的新 Sigma 矩阵(比如:更多行)并使用通过 diag() 计算得到的方形对角矩阵来填充矩阵的前 n×n 部分。

运行这个示例,首先会显示原始矩阵,然后会显示根据 SVD 元素重建的矩阵。

上面使用 Sigma 对角矩阵的复杂之处仅存在于 m 和 n 不相等的情况中。当重建一个方形矩阵时,其对角矩阵可以直接使用,如下。

运行这个示例会显示原来的 3×3 矩阵和根据 SVD 元素直接重建的版本。

用于伪逆的 SVD 

伪逆(pseudoinverse)是将方形矩阵的矩阵求逆泛化应用到行数和列数不相等的矩形矩阵上。这也被称为广义逆(Generalized Inverse)或摩尔-彭若斯逆(Moore-Penrose Inverse),得名于两位独立发现该方法的研究者。

矩阵求逆不是为非方形矩阵定义的。[...] 当 A 的列数大于行数时,那么使用伪逆求解线性方程是众多解决方案中的一种。

——《Deep Learning》,2016 年,第 46 页

伪逆表示为 A^+,其中 A 是被求逆的矩阵,+ 是上标。

伪逆是使用 A 的奇异值分解计算的:

或者,没有点符号:

其中 A^+ 是 A 的伪逆,D^+ 是对角矩阵 Sigma 的伪逆,U^T 是 U 的转置。 

我们可以根据 SVD 运算得到 U 和 V。

根据 Sigma 创建一个对角矩阵,计算 Sigma 中每个非零元素的倒数,然后如果原始矩阵是矩形的就取其转置,就可以计算得到 D^+。

伪逆提供了一种求解线性回归方程的方法,尤其是当行数多于列数时,而这也是很常见的情况。 

NumPy 提供了函数 pinv() 来计算矩形矩阵的伪逆。

下面的示例定义了一个 4×2 的矩阵并计算了其伪逆。

运行这个示例,首先显示定义的矩阵,然后显示计算出的伪逆。

我们可以通过 SVD 采用人工的方式计算伪逆,并将结果与 pinv() 函数的结果进行比较。 

首先我们必须计算 SVD。然后我们必须计算 s 数组中每个值的倒数。然后将这个 s 数组转换成一个对角矩阵,它额外增加了一行 0 以使其变成矩形形式。最后,我们可以根据这些元素计算伪逆。 

具体实现方式为:

下面列出了完整的示例。

运行这个示例,首先显示定义的矩形矩阵,然后显示其伪逆,结果与上面 pinv() 函数的结果一致。

用于降维的 SVD 

SVD 的一大常见应用是降维。 

具有大量特征的数据(比如特征数(列数)多于观察数(行数))也许可以被归约成与所涉预测问题最相关的更小特征子集。

其结果是一个秩更低的矩阵,据说接近原始矩阵。

为了做到这一点,我们可以在原来的数据上执行一次 SVD 操作并选择 Sigma 中前 k 个最大的奇异值。这些列可以从 Sigma 中选择得到,行可以从 V^T 中选择得到。

然后可以重建原始向量 A 的近似 B。

在自然语言处理中,这种方法可以被用在文档中词出现情况或词频的矩阵上,并被称为隐含语义分析(Latent Semantic Analysis)或隐含语义索引(Latent Semantic Indexing)。 

在实践中,我们可以保留和使用被称为 T 的描述性数据子集。这是矩阵的密集总结或投射。

此外,这种变换既可以在原来的矩阵 A 上计算和应用,也可以在其它类似的矩阵上计算和应用。

下面的示例是使用 SVD 的数据归约。

首先定义一个 3×10 的矩阵,其列数多于行数。然后计算 SVD 并且只选取其前两个特征。这些元素再重新结合起来,得到原始矩阵的准确再现。最后计算转换的方式有两种。

运行这个示例,首先显示定义的矩阵,然后是重建的近似矩阵,然后是原始矩阵的两个同样的变换结果。

scikit-learn 提供了直接实现这种功能的 TruncatedSVD 类。 

TruncatedSVD 的创建必须指定所需的特征数或所要选择的成分数,比如 2。一旦创建完成,你就可以通过调用 fit() 函数来拟合该变换(比如:计算 V^Tk),然后再通过调用 transform() 函数将其应用于原始矩阵。结果得到上面被称为 T 的 A 的变换。

下面的示例演示了 TruncatedSVD 类。

运行这个示例,首先显示定义的矩阵,然后是该矩阵变换后的版本。

可以看到,结果得到的值与上面人工计算的结果一致,但某些值的符号不一样。由于所涉及的计算的性质以及所用的基础库和方法的差异,可以预见在符号方面会存在一些不稳定性。只要对该变换进行训练以便复用,这种不稳定性在实践中应该不成问题。

原文链接:https://machinelearningmastery.com/singular-value-decomposition-for-machine-learning/

这篇关于奇异值分解简介:从原理到基础机器学习应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1069962

相关文章

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

C#基础之委托详解(Delegate)

《C#基础之委托详解(Delegate)》:本文主要介绍C#基础之委托(Delegate),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 委托定义2. 委托实例化3. 多播委托(Multicast Delegates)4. 委托的用途事件处理回调函数LINQ

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Java中&和&&以及|和||的区别、应用场景和代码示例

《Java中&和&&以及|和||的区别、应用场景和代码示例》:本文主要介绍Java中的逻辑运算符&、&&、|和||的区别,包括它们在布尔和整数类型上的应用,文中通过代码介绍的非常详细,需要的朋友可... 目录前言1. & 和 &&代码示例2. | 和 ||代码示例3. 为什么要使用 & 和 | 而不是总是使

Python循环缓冲区的应用详解

《Python循环缓冲区的应用详解》循环缓冲区是一个线性缓冲区,逻辑上被视为一个循环的结构,本文主要为大家介绍了Python中循环缓冲区的相关应用,有兴趣的小伙伴可以了解一下... 目录什么是循环缓冲区循环缓冲区的结构python中的循环缓冲区实现运行循环缓冲区循环缓冲区的优势应用案例Python中的实现库

SpringBoot整合MybatisPlus的基本应用指南

《SpringBoot整合MybatisPlus的基本应用指南》MyBatis-Plus,简称MP,是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,下面小编就来和大家介绍一下... 目录一、MyBATisPlus简介二、SpringBoot整合MybatisPlus1、创建数据库和

python中time模块的常用方法及应用详解

《python中time模块的常用方法及应用详解》在Python开发中,时间处理是绕不开的刚需场景,从性能计时到定时任务,从日志记录到数据同步,时间模块始终是开发者最得力的工具之一,本文将通过真实案例... 目录一、时间基石:time.time()典型场景:程序性能分析进阶技巧:结合上下文管理器实现自动计时