奇异值分解在机器学习中经常碰到,今天详细讲讲。本文章中说的"矩阵" / "向量" 都指的是实数矩阵/实数向量,我们只说实数域内的情况。
整数有质因子分解,比如12=2*2*3。分解成2*2*3后,比单单研究12这个数,我们会容易得到一些信息,比如,12这个数不能整除5;一个数 n 乘12后,会整除 2 和 3;等等。
那么矩阵呢,我们是否可以像整数的质因子分解一样进行分解?这样比单单研究这个矩阵也许就会获得很多有用的信息。答案是任何一个矩阵都可以进行奇异值分解,并且奇异值分解很有用。
本篇文章的目录如下:
目录
奇异值分解(Singular Value Decomposition)
我们在说奇异值分解之前,需要先说说特征值分解。
首先,特征分解只适用于方阵。
我们可以定义特征向量。如果一个非0向量 满足
,那么这个非0向量
就是
的特征向量。
一个矩阵 可能没有特征向量,也可能有特征向量。如果有特征向量,也可能有
个线性独立的特征向量,或者
个线性独立的特征向量。
如果一个矩阵 有特征向量,并且有
个线性独立的特征向量,我们可以分析出来一些有用的信息,那可以分析出来什么信息呢?我们可以简单地推导一下:
一、代数性质
我们记这个线性独立的特征向量为
,并且对应的特征值为
。我们将每一个特征向量作为一列拼起来,形成特征向量矩阵
,同理我们把相应的特征值拼成一个向量
,那么我们可以得到:
由于 是 n 阶方阵,并且所有列都相互线性独立,所有
的逆
存在,所有可得:
如果我们将 中的每一列都化为单位向量并且和其他向量都正交,当然此时的
也发生了改变,那么可以得到一个正交矩阵
,由于正交矩阵
,可以得到:
这个式子是我们经常见到的式子,用这个式子推导其他式子都很方便。
二、几何性质
上述都是基于公式推导理解,有没有特征值分解的几何理解呢?我们不妨先基于二维平面做一下分析。
假设 有2个线性独立的特征向量
和
(假设我们已经将这两个特征化简成了正交单位向量),以及对应的特征值
和
。我们可以分析二维平面单位圆上的点,设这个单位圆上每一个点的坐标是
,每一个点的点向量是
,我们都知道
且
。
如果我们给 左乘
得到
向量,该点坐标为
,那么
根据推导出来的式子我们得知 的点坐标为
,
向量的两个点坐标相等,故而
。由于
,所以得
,这是个椭圆呀~,可以下结论了,一个圆上所有点左乘一个
会使得这个圆变成椭圆,并且哪个特征向量的特征值越大,原向量就越偏向哪个特征向量,与这个特征值大的特征向量之间的夹角就会变小,如下图所示:

我们将单位圆上的点推广到二维平面的所有圆上的点(也就是二维平面上的所有点),该点对应的向量左乘都会使该向量发生转变(方向和模都变),
的哪个特征向量的特征值大,转变后的向量就越偏向那个特征向量,与其夹角会变小,并且转变后的向量的模大程度受
的最大特征值的影响。
实对称矩阵一定有n个线性独立特征向量,但是有n个线性独立特征向量的矩阵不一定是实对称矩阵。具体的证明就不在这里说啦,想找证明的话书上找找叭~
只有方阵可以进行特征分解。对于一般的矩阵,可以用奇异值分解进行分解。一个一般的矩阵可以被分解成这样:
(把各个矩阵的维度标出来的话就是
)
其中 :
1、 是
的特征向量矩阵(是正交矩阵);
的列向量称为左奇异向量(left singular vector)。
2、 是
的特征向量矩阵(是正交矩阵);
的列向量称为右奇异向量(right singular vector)。
3、 是对角矩阵,
中对角线上的非0值是
的非0特征值的平方根 ,同时也是
的非0特征值的平方根。(
中对角线上的值从大到小降序排列;
对角线上非0值的个数是
的秩,其<=min(m,n) )。
中非0值称为奇异值(singular value)。
至于奇异值分解基本定理的证明,可以参考李航老师的统计学习方法第二版 第15章 奇异值分解~,写的真的很明白!这里就不证明了。
实对称矩阵的特征值分解的几何解释是:对任意向量 左乘一个实对称矩阵
,则
在同一个空间内会发生缩放变换。当时我们做了推导。
一般矩阵的奇异值分解我们就不仔细推导了,我们简单了解一下。先说结论,的矩阵
表示从 n 维空间
到 m 维空间
的一个线性变换。
给一个向量 左乘一个任意矩阵
,
,我们从后往前看,先对
左乘
,做相同维度 n 上的旋转变换;再在其基础上左乘
,做之前维度 n 上的缩放变换然后拔高/降低维度至 m ;再在其基础上左乘
,做m维度上的旋转变换。
之前说的奇异值分解的式子又称为矩阵
的完全奇异值分解,实际上为了压缩矩阵存储空间,常用的是奇异值分解的紧凑形式和截断形式。紧奇异值分解是与原始矩阵等秩的奇异值分解,截断奇异值分解是比原始矩阵低秩的奇异值分解。
1、紧奇异值分解:
若一般矩阵,其秩为 rank(
) = r , r <=min(m,n),那么
的紧奇异值分解就是:
注意这里是等号哦,其实就是将 原来的
中的 0 项都去掉,只保留 r 个非 0 奇异值构成的对角方阵,其
是
的前 r 列,其
是
的前 r 列。
2、截断奇异值分解:
若一般矩阵,其秩为 rank(
) = r , r <=min(m,n),且 0<k<r ,那么
的截断奇异值分解就是:
注意这里是约等号哦,这里的 是原来的
取前 k 行前 k 列的对角方阵,其
是
的前 k 列,其
是
的前 k 列。
奇异值分解是一种矩阵近似的方法,这个近似是在(Frobenius norm)意义下的对矩阵的最优近似。
矩阵 A 的 Frobenius norm :

具体的证明有点复杂,可参考 李航老师的统计学习方法第二版 第15章 奇异值分解。
有关奇异值分解的应用,有PCA 主成分计算、 LSA 等。
可参考:
主成分分析(PCA)(principal component analysis)
潜在语义分析(LSA)(latent semantic analysis)
呼,终于完事了,今天的奇异值分解到这里就结束啦,欢迎各位大佬留言吖~
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我有一个包含600个模型的Rails应用程序,很快就会增加到800-1000个。我想对Rails应用程序进行分段,以便仅加载某些模型,因此充当单独的应用程序,但所有模型都共享相同的基本模型。是否有执行此操作的标准做法?编辑:我在2.3.8编辑2:问题是许多模型是相似的,但不同之处恰恰足以保证编写一个新类,也就是说,将所有模型都放在一个模型中所需的逻辑将是
我想分解这堆代码,以便我所有的Controller测试(好吧,几乎所有的)都使用这个before(:each)block:before(:each)do@user=User.newcontroller.stub(:authenticate_user!)controller.stub(:current_user).and_return(@user)controller.stub(:add_secure_model_data)end有什么办法吗?我不想将它包含在所有Controller中......因为有一些不需要它。基本上,每个从SecureController扩展的Controller
我正在寻找一种优雅的方式来将存储在哈希中的值分配给预先存在的对象。需要明确的是,如果我有一个对象,比如具有两个属性的obj,比如名称和年龄,我想分配来自哈希的值而不做类似的事情:obj.name=hash[:name]obj.age=hash[:age]感谢您的关注。西蒙妮 最佳答案 最好的办法可能是简单地定义一个像update_attributes这样的方法,它接受一个散列并在类的实例方法中执行它。扩展其他人所写的内容以及您似乎需要的内容我认为您最好的选择是:hash.keys.eachdo|key|m="#{key}="obj.
当事物在ruby中为nil时,是否有将事物分配给哈希的简写或最佳实践?例如,我的问题是我正在使用另一个散列来构建它,如果其中的某些内容为nil,它会将nil分配给该键,而不是让它单独存在。我明白为什么会这样,所以我的解决方案是:hash1[:key]=hash2[:key]unlesshash2[:key].nil?因为我不能在键实际指向nil的has中有一个值。(我宁愿有一个空散列,也不愿有一个有{:key=>nil}的散列,这是不可能发生的)我的问题是有没有更好的方法来做到这一点?我不想在作业结束时执行delete_if。 最佳答案
我总是在我的Railsmodels顶部看到大行代码。我正在寻找用标准Ruby风格分解它们的最佳方法的建议。例如,我现在看到的一行是这样的:delegate:occupation,:location,:picture_url,:homepage_url,:headline,:full_name,:to=>:profile,:prefix=>true,:allow_nil=>true打破这些长方法调用行的传统风格是什么? 最佳答案 简短的回答是视情况。基础知识首先,您可以使用“新的”Ruby哈希语法保存几个字符:result=very_
我有一个数组:'imageIds':imageIds=["778","779","780","781","782"];我想在页面上找到类.preview-image的所有元素,我知道其中的数字将与数组的长度匹配。然后我想为第一个匹配元素分配一个值为imageIds[0]的数据属性“data-img-id”,为第二个匹配元素分配imageIds[1]等。因此最终结果将是转换为:.........etc在此:.........etc不太确定如何形成实现此目的的循环。 最佳答案 选择元素然后使用each循环遍历它们,它将当前元素的索引传递
我有一个具有Guid类型属性的View模型。我需要将它分配给javascript对象属性并将该对象发布到某个操作方法。当我写的时候(在javascript中):varpartyId=@Model.Id;//"Id"isofGuidtype我明白了varpartyId=6abbf77d-ba28-4d8a-87ff-2fa8f8a070c9;//UncaughtSyntaxError:Unexpectedidentifier我该如何处理?我的意思是将Id值分配给javascript变量。 最佳答案 将@Model.Id括在引号内。
我可以用什么把这个字符串转换成数字?“148,326.00美元”我猜我需要分解它并去掉美元符号,然后使用parseFloat()?这是最明智的方法吗?这就是我获取号码的方式:varhomestead=xmlDoc.getElementsByTagName("sc2cash");document.getElementById('num1').innerHTML=homestead[1].textContent; 最佳答案 您需要删除美元符号和逗号,(字符串替换),然后转换为float值试试这个:parseFloat('$148,3
我已经尝试分配不同的数据类型,例如bool值、数字、字符串、对象、空值等,但总是返回false。有什么想法吗? 最佳答案 typeof运算符总是返回一个字符串值。因此,您的原始值必须是一个字符串。字符串的typeof的结果是"string",因此:x="string"typeofx===x//true 关于javascript-您应该将什么JavaScript值分配给变量x以使typeofx===x为真?,我们在StackOverflow上找到一个类似的问题:
这个问题在这里已经有了答案:SplittingupclassdefinitioninES6/Harmony(2个答案)关闭7年前。使用JavaScript“类”(我知道这不是真正的类),可以通过将方法放在单独的文件中来分解一个大的定义,如下所示:varFoo=function(){console.log('initializingfoo');};Foo.prototype.render=require('./render');但是对于ES6类,语法似乎排除了这种方法——似乎方法总是必须在类block中编写为函数文字。我triedthis在6to5REPL中:classFoo{const