Step By Step
1、奇异值分解算法原理简介
2、Code Sample
3、优缺点
一、算法原理简介
SVD算法本质是:将一个比较复杂的矩阵用更小更简单的3个子矩阵的相乘来表示,这3个小矩阵描述了大矩阵重要的特性。
对于奇异值,它跟我们特征分解中的特征值类似,在奇异值矩阵中也是按照从大到小排列,而且奇异值的减少特别的快,在很多情况下,前10%甚至1%的奇异值的和就占了全部的奇异值之和的99%以上的比例。也就是说,我们也可以用最大的k个的奇异值和对应的左右奇异向量来近似描述矩阵。
由于这个重要的性质,SVD可以用于PCA降维,来做数据压缩和去噪。也可以用于推荐算法,将用户和喜好对应的矩阵做特征分解,进而得到隐含的用户需求来做推荐。同时也可以用于NLP中的算法,比如潜在语义索引(LSI)。
二、Code Sample
- 2.1 数据降维测试
from sklearn.datasets import load_iris
from sklearn.decomposition import TruncatedSVD
# 加载数据集
iris = load_iris()
X = iris.data
Y = iris.target
print("------原始数据------")
print(X[:10])
truncatedSVD = TruncatedSVD(3)
result = truncatedSVD.fit_transform(X)
print("------SVD转换后的数据------")
print(result[:10])
back_X = truncatedSVD.inverse_transform(result)
print("------还原后的数据------")
print(back_X[:10])
The Result
------原始数据------
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]
[4.6 3.1 1.5 0.2]
[5. 3.6 1.4 0.2]
[5.4 3.9 1.7 0.4]
[4.6 3.4 1.4 0.3]
[5. 3.4 1.5 0.2]
[4.4 2.9 1.4 0.2]
[4.9 3.1 1.5 0.1]]
------SVD转换后的数据------
[[ 5.91274714 2.30203322 -0.00740154]
[ 5.57248242 1.97182599 -0.24459225]
[ 5.44697714 2.09520636 -0.01502926]
[ 5.43645948 1.87038151 -0.02050488]
[ 5.87564494 2.32829018 0.11033827]
[ 6.47759822 2.32464996 0.23720249]
[ 5.5159752 2.07090423 0.22985312]
[ 5.85092859 2.14807482 -0.01879377]
[ 5.15891972 1.77506408 -0.06103922]
[ 5.64500117 1.99000106 -0.22485292]]
------还原后的数据------
[[5.09900942 3.50097959 1.4014844 0.19767844]
[4.86870364 3.03094925 1.44689807 0.12665275]
[4.69422107 3.20571484 1.30865982 0.18645629]
[4.62518119 3.0750981 1.4622656 0.25901553]
[5.01947963 3.58073643 1.37080948 0.24565314]
[5.40687172 3.89320449 1.68970262 0.41610481]
[4.61617117 3.38400818 1.37576725 0.33789933]
[5.01454656 3.38561478 1.47820176 0.23409183]
[4.40998651 2.89012425 1.38503506 0.22340474]
[4.91842577 3.08177859 1.4723887 0.14318329]]
通过对比看,使用转换后的数据可以很好的还原原始数据。
- 2.2 图片压缩使用示例
import numpy as np
import cv2
from sklearn.decomposition import TruncatedSVD
# jingtian1.jpeg
img = cv2.imread('jingtian1.jpeg')
print('origin image shape is ', img.shape)
def Svd_Compression_Pic(img, k):
res_image = np.zeros_like(img)
for i in range(img.shape[2]):
# 奇异值分解
truncatedSVD = TruncatedSVD(k)
result = truncatedSVD.fit_transform(img[:,:,i]) # 转换后的数据
res_image[:, :, i] = truncatedSVD.inverse_transform(result) # 还原数据
return res_image
res1 = Svd_Compression_Pic(img, k=400)
res2 = Svd_Compression_Pic(img, k=300)
res3 = Svd_Compression_Pic(img, k=100)
res4 = Svd_Compression_Pic(img, k=20)
row11 = np.hstack((res1, res2))
row22 = np.hstack((res3, res4))
res = np.vstack((row11, row22))
cv2.imshow('img', res)
cv2.waitKey(0) # 展示等待,点击任意键继续
cv2.imwrite('svd.png', res) # 保存图片
cv2.destroyAllWindows()
The Result
可以看到,当我们取到前面400个奇异值来重构图片时,基本与原图看不出来差别,甚至100的都可以比较清晰的恢复原图。
三、优缺点
优点
- 简化数据,去除噪声,提高算法的结果;
缺点
- 数据的转换可能难以理解;
适用的数据类型
- 数值型数据。
更多参考
Python机器学习笔记:奇异值分解(SVD)算法
Opencv-Python :图片读取、保存、显示
奇异值分解(SVD)原理与在降维中的应用