数学推导+纯Python实现机器学习算法28:奇异值分解SVD
Posted 机器学习实验室
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数学推导+纯Python实现机器学习算法28:奇异值分解SVD相关的知识,希望对你有一定的参考价值。
Python机器学习算法实现
Author:louwill
Machine Learning Lab
特征值与特征向量
在学习SVD原理之前,我们有必要对矩阵的特征值与特征向量进行回顾。矩阵的特征值与特征向量定义如下:
实际计算时,我们通过求解齐次方程 来计算矩阵 的特征值和特征向量。
将矩阵计算出特征值和特征向量的直接好处就是我们可以将矩阵进行分解,假设矩阵有 个特征值 ,以及每个特征值对应的特征向量 ,那么矩阵 就可以用下式进行分解:
但大多数情况下,我们碰到的矩阵都是非方阵的 的情形。当矩阵行列不等时,如果我们也想对其进行矩阵分解,那就必须使用SVD了。
SVD详解
假设现在我们要对 非方阵 进行矩阵分解,定义分解表达式为:
其中 为 矩阵, 为 对角阵, 为 矩阵。 和 均为酉矩阵,即 和 满足:
SVD的图解示意如下图所示。
由于矩阵 是非方阵,现在将矩阵 与其转置矩阵做矩阵乘法运算,可得到 的方阵 ,然后对该矩阵求特征值和特征向量:
同理,将矩阵 的其转置矩阵与矩阵 做矩阵乘法运算,同样可得 的方阵 ,然后对该矩阵求特征值和特征向量:
左奇异矩阵 和右奇异矩阵 求出来后,我们只剩下中间的奇异值矩阵 尚未求出。奇异值矩阵 除了对角线上的奇异值,其余元素均为0,所以我们只要求出矩阵 的奇异值即可。可推导:
Python SVD实现
import numpy as np
# 创建一个矩阵A
A = np.array([[0,1],[1,1],[1,0]])
# 对其进行SVD分解
u, s, vt = np.linalg.svd(A, full_matrices=True)
print(u.shape, s.shape, vt.shape)
(3, 3) (2,) (2, 2)
# 矩阵u
print(u, s, v.T)
array([[-4.08248290e-01, 7.07106781e-01, 5.77350269e-01],
[-8.16496581e-01, 5.55111512e-17, -5.77350269e-01],
[-4.08248290e-01, -7.07106781e-01, 5.77350269e-01]])
array([1.73205081, 1. ])
array([[-0.70710678, -0.70710678],
[-0.70710678, 0.70710678]])
# 由u,s,v恢复矩阵A
np.dot(u[:,:2]*s, vt)
array([[ 1.11022302e-16, 1.00000000e+00],
[ 1.00000000e+00, 1.00000000e+00],
[ 1.00000000e+00, -3.33066907e-16]])
SVD图像压缩
import numpy as np
import os
from PIL import Image
from tqdm import tqdm
# 定义恢复函数,由分解后的矩阵恢复到原矩阵
def restore(u, s, v, K):
'''
u:左奇异矩阵
v:右奇异矩阵
s:奇异值矩阵
K:奇异值个数
'''
m, n = len(u), len(v[0])
a = np.zeros((m, n))
for k in range(K):
uk = u[:, k].reshape(m, 1)
vk = v[k].reshape(1, n)
# 前k个奇异值的加总
a += s[k] * np.dot(uk, vk)
a = a.clip(0, 255)
return np.rint(a).astype('uint8')
A = np.array(Image.open("./ml_lab.jpg", 'r'))
# 对RGB图像进行奇异值分解
u_r, s_r, v_r = np.linalg.svd(A[:, :, 0])
u_g, s_g, v_g = np.linalg.svd(A[:, :, 1])
u_b, s_b, v_b = np.linalg.svd(A[:, :, 2])
# 使用前50个奇异值
K = 50
output_path = r'./svd_pic'
# 恢复图像
for k in tqdm(range(1, K+1)):
R = restore(u_r, s_r, v_r, k)
G = restore(u_g, s_g, v_g, k)
B = restore(u_b, s_b, v_b, k)
I = np.stack((R, G, B), axis=2)
Image.fromarray(I).save('%s\svd_%d.jpg' % (output_path, k))
往期精彩:
一个算法工程师的成长之路
长按二维码.关注机器学习实验室
喜欢您就点个在看!
以上是关于数学推导+纯Python实现机器学习算法28:奇异值分解SVD的主要内容,如果未能解决你的问题,请参考以下文章
机器学习强基计划8-3:详细推导核化主成分分析KPCA算法(附Python实现)