降維(PCA、核PCA、SVD、高斯隨機對映 和 NMF)
阿新 • • 發佈:2019-02-11
以下內容來自《Python資料科學指南》
降維方法比較:
降維方法比較:
- PCA:計算代價高昂,特徵向量得存線上性相關。
- 核PCA: 特徵向量是非線性相關也可以。
- SVD:比PCA更能解釋資料,因為是直接作用於原資料集,不會像PCA一樣,將相關變數轉換為一系列不相干的變數。另外,PCA是單模因子分析方法,行列代表的是相同的實體,而SVD是雙模因子(即適用兩類實體矩陣),可以運用在文字挖掘中,行對應詞,列對應文件。
- 高斯隨機對映:速度快,利用歐氏距離降維,但資料多會有記憶體問題,可以考慮稀疏隨機對映代替。
- NMF:常見於推薦系統,輸入矩陣A = 降維矩陣(行)A_dash * 成本矩陣(列) F。
- 將資料集中心化;
- 找出資料集的相關矩陣和單位標準偏差值;
- 將相關矩陣分解成它的特徵向量和值;
- 基於降序的特徵值選擇Top-N特徵向量;
- 投射輸入的特徵向量矩陣到一個新空間。
2. 核PCA:針對非線性資料集進行降維。核類別有:線性、多項式、sigmoid、餘弦值、預先計算的、RBF。# -*- coding: utf-8 -*- """ Created on Fri Mar 30 17:47:41 2018 @author: Alvin AI """ from sklearn.datasets import load_iris import numpy as np import matplotlib.pyplot as plt import scipy from sklearn.preprocessing import scale data = load_iris() x = data['data'] y = data['target'] x_s = scale(x,with_mean=True,with_std=True,axis=0)#中心化 x_c = np.corrcoef(x_s.T)#計算過相關矩陣 eig_val,r_eig_vec = scipy.linalg.eig(x_c) print 'Eigen values \n%s' % (eig_val)#相關矩陣中找到的特徵值 print '\n Eigen vectors \n%s' % (r_eig_vec)#相關矩陣中找的特徵向量 #可解釋變化的百分比=特徵值/原特徵變數的個數,這裡是4個變數 w = r_eig_vec[:,0:2]#選擇前兩個特徵向量,因為輸出結果Eigen values的前兩個特徵值較大 x_rd = x_s.dot(w)#叉乘,四維變二維y plt.figure(1) plt.scatter(x_rd[:,0],x_rd[:,1],c=y) plt.xlabel('component 1') plt.ylabel('component 2') #如何選擇多少成分的方法 print "Component, Eigen Value, % of Variance, Cumulative %" cum_per = 0 per_var = 0 for i,e_val in enumerate(eig_val): per_var = round((e_val/len(eig_val)),3) cum_per += per_var print ('%d, %0.2f, %0.2f, %0.2f')%(i+1, e_val, per_var*100, cum_per*100) #輸出結果: Eigen values #特徵值 [2.91081808+0.j 0.92122093+0.j 0.14735328+0.j 0.02060771+0.j] Eigen vectors #特徵向量 [[ 0.52237162 -0.37231836 -0.72101681 0.26199559] [-0.26335492 -0.92555649 0.24203288 -0.12413481] [ 0.58125401 -0.02109478 0.14089226 -0.80115427] [ 0.56561105 -0.06541577 0.6338014 0.52354627]] #可解釋變化的百分比=特徵值/原特徵變數的個數,這裡是4個變數 #2.91/4=72.80 #第一個成分可解釋72.80%,第二個成分可解釋23%,前兩份成分一起可以解釋95.8% Component, Eigen Value, % of Variance, Cumulative % 1, 2.91, 72.80, 72.80 2, 0.92, 23.00, 95.80 3, 0.15, 3.70, 99.50 4, 0.02, 0.50, 100.00
3. 奇異值分解:Singular Value Decomposition, SVD, 與PCA不同,直接作用於原始資料矩陣。SVD把m*n矩陣分解成三個矩陣的乘積:A = U*S*V^T 。from sklearn.datasets import make_circles import matplotlib.pyplot as plt import numpy as np from sklearn.decomposition import PCA #PCA模組 from sklearn.decomposition import KernelPCA #核PCA模組 #生成一個變化非線性的資料集 np.random.seed(10)#定義一個隨機種子號 x,y = make_circles(n_samples=400, factor=.2, noise=0.02)#factor代表維度 plt.close('all')#關閉當前所有圖 plt.figure(1) plt.title('original space') plt.scatter(x[:,0],x[:,1],c=y) plt.xlabel('$x_1$') plt.ylabel('$x_2$') #使用PCA降維 pca = PCA(n_components=2) pca.fit(x) x_pca=pca.transform(x) #繪製前兩個主成分的圖 plt.figure(2) plt.title('pca') plt.scatter(x_pca[:,0],x_pca[:,1],c=y) plt.xlabel('$x_1$') plt.ylabel('$x_2$') #將兩個成分單獨拎出來畫,發現結果均對映在一條直線上,無法實現區分 class_1_index = np.where(y==0)[0] class_2_index = np.where(y==1)[0] plt.figure(3) plt.title('pca-one component') plt.scatter(x_pca[class_1_index,0],np.zeros(len(class_1_index)),color='red') plt.scatter(x_pca[class_2_index,0],np.zeros(len(class_2_index)),color='blue') #使用kernal PCA #這裡核PCA呼叫的核是徑向基函式(Radial Basis Function, RBF) #gamma值為10,gamma是一個核(用於處理非線性)引數--核心係數 kpca = KernelPCA(kernel='rbf',gamma=10) x_kpca = kpca.fit_transform(x) plt.figure(4) plt.title('kernel pca') plt.scatter(x_kpca[:,0],x_kpca[:,1],c=y) plt.xlabel('$x_1$') plt.ylabel('$x_2$')
- U:左奇異矩陣,m*k矩陣。
- V:右奇異矩陣,n*k矩陣。
- S:該矩陣的對角線值為奇異值,k*k矩陣。
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from sklearn.preprocessing import scale
from scipy.linalg import svd
data = load_iris()
x = data['data']
y = data['target']
#只中心化,不需要把資料縮放到同一量綱
#因為現在的資料就是相同度量單位,不縮放還能捕捉到最大變化的基本單位
x_s = scale(x,with_mean=True,with_std=False,axis=0)
#用SVD分解矩陣
#沒必要縮放資料,full_matrices=False是一定要有的
U,S,V = svd(x_s,full_matrices=False)
#選擇最前兩個奇異值來近似原始的矩陣
x_t = U[:,:2]
#最後用降維的成分來繪製出資料集的圖形
plt.figure(1)
plt.scatter(x_t[:,0],x_t[:,1],c=y)
plt.xlabel("Component 1")
plt.ylabel("Component 2")
plt.show()
4. 高斯隨機對映:速度快,利用資料間的距離來降低維度。# -*- coding: utf-8 -*-
"""
Created on Mon Apr 23 21:19:54 2018
@author: Alvin AI
"""
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import euclidean_distances
from sklearn.random_projection import GaussianRandomProjection
import matplotlib.pyplot as plt
#載入20個新聞租資料集
#我們只選用sci.crypt分類
#其他分類還包括“sci.med” "sci.space"等
cat = ['sci.crypt']
data = fetch_20newsgroups(categories=cat)
#從上面的資料集中建立一個詞-文件矩陣,詞頻作為值,不哦那個idf
vectorizer = TfidfVectorizer(use_idf=False)
vector = vectorizer.fit_transform(data.data)
#執行對映,我們把維度降為1000
gauss_proj = GaussianRandomProjection(n_components=1000)
vector_t = gauss_proj.fit_transform(vector)
#打印出轉換後的向量形態
print vector.shape
print vector_t.shape
#為了驗證轉換過程是否保持了距離,我們計算新的和舊的兩點間距離
org_dist = euclidean_distances(vector)
red_dist = euclidean_distances(vector_t)
diff_dist = abs(org_dist-red_dist)
#繪製差距熱圖(只有前100個文件)
plt.figure()
plt.pcolor(diff_dist[0:100,0:100])
plt.colorbar()
plt.show()
5. 非負矩陣分解:Non-negative Matrix Factorization, NMF 。常用於推薦系統,預測原本缺失的資料。# -*- coding: utf-8 -*-
"""
Created on Sat Mar 31 15:04:36 2018
@author: Alvin AI
"""
import numpy as np#
#from collections import dafaultdict
from sklearn.decomposition import NMF
import matplotlib.pyplot as plt
#生成電影評分資料集
ratings = [\
[1,2,3,5,2,1],\
[2,3,1,1,2,1],\
[4,2,1,3,1,4],\
[2,9,5,4,2,1],\
[1,4,2,1,1,1]]
movie_dict = {1:'alvin story',
2:'star wars',
3:'inception',
4:'gunsa',
5:'dream',
6:'decomere'}
A = np.asmatrix(ratings,dtype=float)#向量化
max_components = 2
reconstruction_error = []
nmf = None
nmf = NMF(n_components = max_components, random_state=1) #降維到2
A_dash = nmf.fit_transform(A)#A_dash為降維矩陣,針對於行例項,即使用者
for i in range(A_dash.shape[0]):
print 'User id = %d, comp1 score = %0.2f, comp2 score = \
%0.2f' % (i+1,A_dash[i][0],A_dash[i][1])
#輸入矩陣A=A_dash*F
#A_dash為降維矩陣,針對於行例項,即使用者
plt.figure(1)
plt.title('user concept mapping')
x = A_dash[:,0]
y = A_dash[:,1]
plt.scatter(x,y)
plt.xlabel('component1')
plt.ylabel('component2')
#F為成本矩陣,針對列例項,即電影
F =nmf.components_
plt.figure(2)
plt.title('movie concept mapping')
x = F[0,:]
y = F[1,:]
plt.scatter(x,y)
plt.xlabel('component1')
plt.ylabel('component2')
for i in range(F[0,:].shape[0]):
plt.annotate(movie_dict[i+1],(F[0,:][i],F[1,:][i]))#在圖中給每個點加上電影名註釋
plt.show()
#預測出電影評分,如果原輸入矩陣有些是0,而在下面結果輸出會預測出使用者評分
reconstructed_A = np.dot(A_dash,F)
np.set_printoptions(precision=2)#精確到小數點後2位
print reconstructed_A