主成分分析
原理
通俗地講腔召,主成分分析(PCA)的原理是數(shù)據(jù)集旋轉(zhuǎn)(可以是高維)后,使前面的特征對應(yīng)的值的方差盡量大请祖,只取前面若干個特征達到降維的目的馒疹。
方法:求出數(shù)據(jù)集的散度矩陣,求出它的特征值和特征向量滔韵,使用最大的K個(數(shù)量自定)特征值對應(yīng)的特征向量作為基逻谦,使用矩陣乘法直接求出數(shù)據(jù)集變換后的結(jié)果。
參考鏈接
PCA csdn
PCA zhihu
劉建平大佬:SVD 順便吹一波這位陪蜻,資料很全推導很詳細
作用
PCA和類似的降維算法有很大作用
- 數(shù)據(jù)降維:對高維數(shù)據(jù)進行降維邦马,減輕機器學習的計算量。
- 數(shù)據(jù)可視化:高維的數(shù)據(jù)不利于人類的觀察宴卖,故常常降維到二維或者三維
- 圖像壓縮:將一些眼睛難以察覺的細節(jié)去除滋将,常見圖像使用PCA的壓縮率能夠達到50%以上,而不損失大量細節(jié)症昏。
- 數(shù)據(jù)降噪随闽,包括圖像降噪:噪聲數(shù)據(jù)的方差一般比較小,而信號數(shù)據(jù)的方差一般比較大肝谭,所以PCA能夠去除噪聲掘宪。
python實現(xiàn)
由于PCA算法不依賴于數(shù)據(jù)集,無需進行訓練等分苇,故封裝為一個函數(shù)添诉。
#pca.py
import numpy as np
def pca(X:np.ndarray, K:int, debug:bool=False)->np.ndarray:
if np.shape(X)[1] <= K:
print("[-] dim too low");return
if K <= 0:
print("[-] K not valid");return
# centering the data
X_avg = np.average(X, axis=0)
X_centered = X - X_avg
# covariance matrix
cov_mat = X_centered @ X_centered.T
eigval, eigvec = np.linalg.eig(cov_mat)
eigval_target = eigval[0:K]
eigvec_target = eigvec[:, 0:K]
if debug : print(eigval, eigvec)
if debug : print(np.linalg.norm(np.abs(eigvec_target), axis=0))
# print(np.linalg.norm(eigvec/np.linalg.norm(eigvec, ord=2, axis=1), ord=2, axis=1))
# print(eigval_target, eigvec_target)
return np.array(cov_mat @ eigvec_target, dtype=np.float64)
測試上述代碼,使用三維特征的數(shù)據(jù)集進行測試医寿。
#main.py
import pca
import numpy as np
X = np.array(
[
[0., 0., 2.],
[1., 1., 3.],
[2., 2., 5.],
[-1., 0., 5.],
[4., 3., 2.]
])
print(pca.pca(X, 2))
測試結(jié)果如下所示
ComplexWarning: Casting complex values to real discards the imaginary part
return np.array(cov_mat @ eigvec_target, dtype=np.float64)
[[ 5.45643859 5.30087165]
[ 0.66197922 1.3243035 ]
[ -2.64791688 -5.29721401]
[ 13.72678804 -2.15574602]
[-17.19728897 0.82778488]]
可以看到對數(shù)據(jù)實現(xiàn)了降維
相關(guān)算法的應(yīng)用
對圖片進行壓縮栏赴,原理見劉建平文
其中應(yīng)用了SVD(奇異值分解),SVD也可以用于PCA降維
#svd.py
def image_compress_pca_svd(X:np.ndarray, K:int, debug:bool=False)->np.ndarray:
if len(np.shape(X)) != 2 : print("just support 2d data");return
u, sigma, vh = np.linalg.svd(X)
if debug:print(np.shape(sigma), "sigma shape")
if debug:print(np.shape(u), np.shape(sigma), np.shape(vh))
u[:, K:] = 0
vh[K:, :] = 0
s = np.zeros(np.shape(X), X.dtype)
for i in range(K):
s[i, i] = sigma[i]
return u @ s @ vh
利用圖片進行測試
分別對三個通道進行壓縮靖秩,之后進行還原须眷,查看效果
#compress.py
import pca
import numpy as np
import matplotlib.pyplot as plt
img = plt.imread("what.jpg")
r = img[:, :, 0]
g = img[:, :, 1]
b = img[:, :, 2]
plt.imshow(img)
plt.show()
r1 = pca.image_compress_pca_svd(r, 400)
g1 = pca.image_compress_pca_svd(g, 400)
b1 = pca.image_compress_pca_svd(b, 400)
img1 = np.ndarray(np.shape(img), img.dtype)
img1[:, :, 0] = r1
img1[:, :, 1] = g1
img1[:, :, 2] = b1
# cv2.imshow("img1", img1)
plt.imshow(img1)
plt.show()
壓縮前后圖像
壓縮前
壓縮后
可以看出基本上還原了圖片的效果而沒有肉眼可見的損失
總結(jié)
- PCA降維算法是一種重要的數(shù)據(jù)處理方法
- SVD具有實際用途竖瘾,是一種樸素的壓縮方法,對于第二個維度的壓縮花颗,可以作為一種降維方法
- 實現(xiàn)起來也真方便:)