七、SVD进行数据压缩
🚩根据奇异值分解,进行数据压缩,以图片为例进行展示:
首先我们需要下载一张图片:
链接:https://pan.baidu.com/s/1pyywQWO4U4WWxtuAhAQHMQ?pwd=l7vv
提取码:l7vv
import numpy as np import matplotlib.pyplot as plt # 图片压缩 def pic_compress(r, img): u, sigma, vt = np.linalg.svd(img) compress_img = np.dot(np.dot(u[:, :r], np.diag(sigma[:r])), vt[:r, :])# 还原图像 size = u.shape[0] * r + r * r + r * vt.shape[1] # 压缩后大小 return compress_img, size filename = './bird.jpg' img = plt.imread(filename)[:, :, 0] # 取其中的一个颜色通道 compress_img, size = pic_compress(30, img) print('原图尺寸:' + str(img.shape[0] * img.shape[1])) print('压缩尺寸:' + str(size)) # 图片绘制 fig, ax = plt.subplots(1, 2,figsize = (12,4)) ax[0].imshow(img,cmap = 'gray') ax[0].set_title('before compress') ax[1].imshow(compress_img,cmap = 'gray') ax[1].set_title('after compress') plt.show()
八、SVD进行PCA降维
import numpy as np from sklearn import datasets r = 2 # 筛选特征个数 X,y = datasets.load_iris(return_X_y = True) print('原始数据特征个数是:', X.shape[1]) # 1、去中心化 mean_ = np.mean(X, axis=0) X -= mean_ # 2、奇异值分解 u, s, v = np.linalg.svd(X) # 3、符号翻转(如果为负数,那么变成正值) max_abs_cols = np.argmax(np.abs(u), axis = 0) display(max_abs_cols) signs = np.sign(u[max_abs_cols, range(u.shape[1])]) display(signs) u *= signs # 4、降维特征筛选 u = u[:, :r] # 5、归一化 u = (u - u.mean(axis = 0)) / u.std(axis = 0, ddof = 1) # ddof计算样本标准差 display(u[:5]) print('经过PCA降维,数据特征个数是:', u.shape[1])
九、SVD进行矩阵求逆
9.1 SVD求逆矩阵原理
🚩在矩阵求逆过程中,矩阵通过 S V D 转换到正交空间。不同得奇异值和奇异值向量代表了矩阵中不同的线性无关(或独立)项。对矩阵进行 S V D 分解,形式如下所示:
奇异值矩阵为:
奇异值矩阵逆矩阵为:
从上面可以看出,S V D 求逆是原始奇异值的倒数,这就使得通过 S V D 对矩阵求逆变得非常简单:奇异值求倒数,奇异矩阵转置。
9.2 SVD求逆代码演示
import numpy as np A = np.array([[ 3, 4, 5, 5], [ 7, 5, 3, 6], [ 6, 5, 7, 7], [ 4, 9, 8, 9], [ 5, 10, 5, 7]]) # A是奇异矩阵 print('矩阵A的形状是:', A.shape) print('矩阵A的秩是:') display(np.linalg.matrix_rank(A)) display(np.linalg.inv(A)) # 无法直接求解逆矩阵
使用奇异值分解,进行逆矩阵求解
import numpy as np import warnings warnings.filterwarnings('ignore') A = np.array([[ 3, 4, 5], [ 7, 5, 3], [ 6, 5, 7], [ 4, 9, 8], [ 5, 10, 5]]) u, s, v = np.linalg.svd(A) display(u, s, v) m, n = A.shape # 奇异值求倒数 # sigma = np.concatenate([np.diag(s),np.full(shape = (m-n,n),fill_value = 0)],axis = 0) # sigma = sigma**(-1) # cond = np.isinf(sigma) # sigma[cond] = 0 sigma = np.diag(np.concatenate([s**(-1),[0]*(m-n)]))[:,:3] # 逆矩阵求解 B = v.T.dot(sigma.T).dot(u.T) print('矩阵B是A的逆矩阵,两个进行矩阵运算得到单位矩阵:') display(B.dot(A).round(5))
十、SVD进行协同过滤
10.1 协同过滤
🚩协同过滤是一种从大量用户给出的兴趣爱好集合中预测用户的偏好和兴趣的技术。 它的基本假设是,对某个事物,人们过去喜欢那么将来也会喜欢。 协作过滤可以用于推荐系统,该推荐系统自动向用户建议他/她的首选产品。
推荐系统的任务就是联系用户和信息,一方面帮助用户发现对自己有价值的信息,而另一方面让信息能够展现在对它感兴趣的用户面前,从而实现信息消费者和信息生产者的双赢。
10.2 干饭人
🚩下面是用户午餐点外卖倾向评分,分值1~5,分值越大表示倾向越大。0表示数据缺失,需要你使用SVD分解,将缺失值,进行补全,预测。数据如下:
外卖意向 | 寿司 | 牛肉拉面 | 麻辣烫 | 黄焖鸡米饭 | 排骨饭 |
张三 | 2 | 1 | 3 | 2 | 5 |
李四 | 3 | 5 | 2 | 4 | 3 |
王五 | 1 | 3 | 1 | 1 | 4 |
赵六 | 0 | 2 | 4 | 5 | 2 |
Michael | 4 | 4 | 5 | 0 | 5 |
Sara | 5 | 5 | 2 | 3 | 1 |
John | 1 | 1 | 4 | 2 | 2 |
Daniel | 2 | 4 | 3 | 5 | 4 |
Po | 1 | 3 | 3 | 2 | 1 |
辰chen | 5 | 0 | 1 | 3 | 5 |
奇异值分解算法可以用于矩阵近似问题。如果分解时,中间的矩阵取部分特征值(只取前面若干个最大的特征值),这样就可以对原矩阵进行近似了。基于这种思想,奇异值分解可以用于预测用户对外卖点餐的倾向评分。
10.3 SVD进行协同过滤
import numpy as np food = np.mat([[2, 1, 3, 2, 5], [3, 5, 2, 4, 3], [1, 3, 1, 1, 4], [0, 2, 4, 5, 2], [4, 4, 5, 0, 5], [5, 5, 2, 3, 1], [1, 1, 4, 2, 2], [2, 4, 3, 5, 4], [1, 3, 3, 2, 1], [5, 0, 1, 3, 5]]) u, sigma, v = np.linalg.svd(food) # 选取前2大特征值,做近似表达 food_result = np.mat(u[:, :2]) * np.mat(np.diag(sigma[:2])) * np.mat(v[:2, :]) food_result.round(1)
根据SVD分解,对缺失值数据,进行了预测,结果如下:
外卖意向 | 寿司 | 牛肉拉面 | 麻辣烫 | 黄焖鸡米饭 | 排骨饭 |
张三 | 2 | 1 | 3 | 2 | 5 |
李四 | 3 | 5 | 2 | 4 | 3 |
王五 | 1 | 3 | 1 | 1 | 4 |
赵六 | 1.2 | 2 | 4 | 5 | 2 |
Michael | 4 | 4 | 5 | 2.3 | 5 |
Sara | 5 | 5 | 2 | 3 | 1 |
John | 1 | 1 | 4 | 2 | 2 |
Daniel | 2 | 4 | 3 | 5 | 4 |
Po | 1 | 3 | 3 | 2 | 1 |
辰chen | 5 | 1.4 | 1 | 3 | 5 |