机器学习-降维之奇异值分解SVD算法原理及实战
生活随笔
收集整理的這篇文章主要介紹了
机器学习-降维之奇异值分解SVD算法原理及实战
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
奇異值分解
- 簡介
- PCA是通過特征值分解來進行特征提取的,但它要求矩陣必須是方陣,但在實際應用場景中,經常遇到的矩陣都不是方陣,如N個學生,每個學生有M門課程,其中N!=M, 這就組成了一個M*N的非方陣矩陣,這種情況下無法使用主成分分析,也限制了特征值分解方法的使用。而奇異值分解(SVD),是線性代數中重要的一種矩陣分解,該方法對矩陣的形狀沒有要求。
- 原理
- 在很多情況下,數據的一小段攜帶了數據集中大部分信息,而剩下的信息則要么是噪聲,要么是毫不相關的信息。利用SVD實現,能夠用小得多的數據集來表示原始數據集。這樣做,實際上是去除了噪聲和冗余數據。同樣,當用戶試圖節省空間時,去除信息也是很有用的。
- 假設是一個階矩陣,則存在一個分解使得:Mm×n=Um×n∑m×nVn×nTM_{m \times n} = U_{m \times n} \sum_{m \times n} V_{n \times n}^T Mm×n?=Um×n?m×n∑?Vn×nT?
- 式子中,為m×mm\times mm×m階酉矩陣;∑\sum∑為半正定m×nm\times nm×n階對角矩陣;而VTV^TVT,即V的共軛轉置,是n*n階酉矩陣。這樣的分解就稱為M的奇異值分解。∑\sum∑對角線上的元素∑i\sum i∑i,其中i即為M的奇異值。常見的做法是奇異值從大到小排列。
- 奇異值的優點是:可以簡化數據,壓縮維度,去除噪聲數據,提升算法結果。加快模型計算性能,可以針對任一普通矩陣進行分解(包括樣本數小于特征數),不受限于方陣。
- 奇異值的缺點是:轉化后的數據難以理解,如何與具體業務知識對應起來是難點。
- 那么在解決實際問題時如何知道保留多少個奇異值呢?
- 一個典型的做法就是保留矩陣中90%的能量信息。為了計算總能量信息,將所有的奇異值求其平方和。于是可以將奇異值的平方和累加到總值的90%為止。
- 實戰
- 使用奇異值分解進行圖像壓縮
- u, sigma, v = np.linalg.svd(M)
- 其中u和v返回矩陣M的左右奇異向量,sigma返回奇異值從大到小排列的一個向量。
- 前置知識
- 一般彩色圖像就是RGB三個圖層上矩陣的疊加,每個元素值為0~255,plt可以直接讀取圖像,對三個圖層一一處理即可。
- SVD進行壓縮步驟
- 讀取圖片,分解為RGB三個矩陣。
- 對三個矩陣分別進行SVD分解,得到對應的奇異值和奇異向量。
- 按照一定的標準進行奇異值篩選(整體數量的一定百分比,或者奇異值和的一定百分比)。
- 恢復矩陣。
- 保存圖像。
- 代碼
- # -*-coding:utf-8-*-import numpy as npfrom matplotlib import pyplot as pltdef svdimage(filename, percent):"""讀取原始圖像數據:param filename::param percent::return:"""original = plt.imread(filename) # 讀取圖像R0 = np.array(original[:, :, 0]) # 獲取第一層矩陣數據G0 = np.array(original[:, :, 1]) # 獲取第二層矩陣數據B0 = np.array(original[:, :, 2]) # 獲取第三層矩陣數據u0, sigma0, v0 = np.linalg.svd(R0) # 對第一層數據進行SVD分解u1, sigma1, v1 = np.linalg.svd(G0) # 對第二層數據進行SVD分解u2, sigma2, v2 = np.linalg.svd(B0) # 對第三層數據進行SVD分解R1 = np.zeros(R0.shape)G1 = np.zeros(G0.shape)B1 = np.zeros(B0.shape)total0 = sum(sigma0)total1 = sum(sigma1)total2 = sum(sigma2)# 對三層矩陣逐一分解sd = 0for i, sigma in enumerate(sigma0): # 用奇異值總和的百分比來進行篩選R1 += sigma * np.dot(u0[:, i].reshape(-1, 1), v0[i, :].reshape(1, -1))sd += sigmaif sd >= percent * total0:breaksd = 0for i, sigma in enumerate(sigma1): # 用奇異值總和的百分比來進行篩選G1 += sigma * np.dot(u1[:, i].reshape(-1, 1), v1[i, :].reshape(1, -1))sd += sigmaif sd >= percent * total1:breaksd = 0for i, sigma in enumerate(sigma2): # 用奇異值總和的百分比來進行篩選B1 += sigma * np.dot(u2[:, i].reshape(-1, 1), v2[i, :].reshape(1, -1))sd += sigmaif sd >= percent * total2:breakfinal = np.stack((R1, G1, B1), 2)final[final > 255] = 255final[final < 0] = 0final = np.rint(final).astype('uint8')return finalif __name__ == '__main__':filename = 'data/example.jpg'for p in np.arange(.1, 1, .1):print('percent is {}'.format(p))after = svdimage(filename, p)plt.imsave('data/' + str(p) + '_1.jpg', after)
- 運行效果(不同壓縮比下)
- 補充說明
- 參考書為《Python3數據分析與機器學習實戰》,對部分錯誤修改
- 具體數據集和代碼見我的Github,歡迎Star或者Fork
總結
以上是生活随笔為你收集整理的机器学习-降维之奇异值分解SVD算法原理及实战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习-降维之主成分分析PCA算法原理
- 下一篇: 机器学习-聚类之K均值(K-means)