1、SVD分解
1、描述
在代码中使用到了一些图片,大家只需要将图片放到pycharm指定的路径中既可以使用,为了方便大家的学习,现将图片保存到博客的资源中,资源路径如下:
https://download.csdn.net/download/weixin_43334389/13569487
2、代码
# @Time : 2020/12/7 15:19
# @Description : 对图片进行SVD奇异值分解代码
import numpy as np
import os
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib as mpl
from pprint import pprint
def restore1(sigma, u, v, K):
"""
@desc:
@param sigma:奇异值
@param u:左特征向量
@param v:右特征向量
@param K:需要的维度信息
@return:返回一个在k(k<n)维度下的图像
"""
m = len(u)
n = 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)
# a为(m*n)的矩阵,将左右特征向量转化尺寸后
a += sigma[k] * np.dot(uk, vk)
a[a < 0] = 0
a[a > 255] = 255
return np.rint(a).astype('uint8')
def restore2(sigma, u, v, K):
# 列向量
m = len(u)
# 行向量
n = len(v[0])
a = np.zeros((m, n))
for k in range(K + 1):
for i in range(m):
# u的列向量和v的每一行向量进行相乘
# a[0] = sigma * u的第一列的第一个值 * v的第一行所对应的向量
# a一共有m行
a[i] += sigma[k] * u[i][k] * v[k]
a[a < 0] = 0
a[a > 255] = 255
return np.rint(a).astype('uint8')
if __name__ == "__main__":
# 引入照片的路径
A = Image.open("son.png", 'r')
print(A)
# 输出路径
output_path = r'.\Pic'
if not os.path.exists(output_path):
os.mkdir(output_path)
a = np.array(A)
print(a.shape)
K = 50
u_r, sigma_r, v_r = np.linalg.svd(a[:, :, 0])
u_g, sigma_g, v_g = np.linalg.svd(a[:, :, 1])
u_b, sigma_b, v_b = np.linalg.svd(a[:, :, 2])
plt.figure(figsize=(10, 10), facecolor='w')
mpl.rcParams['font.sans-serif'] = [u'simHei']
mpl.rcParams['axes.unicode_minus'] = False
# 取前k个特征(R,G,B这三个通道),再将图像拼出来
for k in range(1, K + 1):
R = restore1(sigma_r, u_r, v_r, k)
G = restore1(sigma_g, u_g, v_g, k)
B = restore1(sigma_b, u_b, v_b, k)
I = np.stack((R, G, B), axis=2)
Image.fromarray(I).save('%s\\svd_%d.png' % (output_path, k))
if k <= 12:
plt.subplot(3, 4, k)
# 负责对图像进行处理,并显示其格式
plt.imshow(I)
# 关闭坐标轴
plt.axis('off')
plt.title(u'奇异值个数:%d' % k)
plt.suptitle(u'SVD与图像分解', fontsize=20)
# 会自动调整子图参数,使之填充整个图像区域
plt.tight_layout(0.3, rect=(0, 0, 1, 0.92))
plt.show()
3、结果展示
2、QR分解
1、描述
使用QR分解计算A矩阵的特征值,原理:对A一直求合同,上三角矩阵会越来越弱,最后Ak只剩下对角线上的值,此时Ak对角线上的值即为特征值,也为A的特征值。
2、代码
# @Time : 2020/12/7 17:47
# @Description : 使用QR分解计算特征值
import math
import numpy as np
def is_same(a, b):
"""
@desc: 比较a_k和a_k+1这两个矩阵对角线上的值,如果很相近就结束迭代。
@param a:r,q相乘得到的矩阵对角线上的值
@param b:是上一个a对应的矩阵对角线上的值
@return:
"""
n = len(a)
for i in range(n):
if math.fabs(a[i] - b[i]) > 1e-6:
return False
return True
if __name__ == "__main__":
a = np.array([0.65, 0.28, 0.07, 0.15, 0.67, 0.18, 0.12, 0.36, 0.52])
n = int(math.sqrt(len(a)))
# 3*3矩阵
a = a.reshape((n, n))
# 特征值,特征向量
value, v = np.linalg.eig(a)
times = 0
# 返回True时结束迭代过程
# 随着迭代次数的进行,a对应的对角阵r上三角部分会越来越弱(特征值),最后对角线
# 的值即为特征值
while (times == 0) or (not is_same(np.diag(a), v)):
# 对角矩阵的值
v = np.diag(a)
q, r = np.linalg.qr(a)
# qr分解
a = np.dot(r, q)
times += 1
print("正交阵:\n", q)
print("三角阵:\n", r)
print("近似阵:\n", a)
print("次数:", times, "近似值:", np.diag(a))
print("精确特征值:", value)
3、结果展示
最后一次控制台输出:
正交阵:
[[-1.00000000e+00 2.14199684e-05 -1.59459985e-09]
[-2.14199681e-05 -9.99999995e-01 -1.01004056e-04]
[-3.75810352e-09 -1.01004056e-04 9.99999995e-01]]
三角阵:
[[-9.99998810e-01 -2.68197256e-02 2.26014254e-01]
[ 0.00000000e+00 -5.18489185e-01 -7.96303223e-05]
[ 0.00000000e+00 0.00000000e+00 3.21511428e-01]]
近似阵:
[[ 9.99999383e-01 2.67754771e-02 2.26016964e-01]
[ 1.11060221e-05 5.18489190e-01 -2.72608113e-05]
[-1.20827323e-09 -3.24739582e-05 3.21511427e-01]]
次数: 17 近似值: [0.99999938 0.51848919 0.32151143]
精确特征值: [1. 0.51848858 0.32151142]