1. 程式人生 > >PCA降維例項[GridSearchCV求最優參]

PCA降維例項[GridSearchCV求最優參]

降維概念

       機器學習領域中所謂的降維就是指採用某種對映方法,將原高維空間中的資料點對映到低維度的空間中。降維的本質是學習一個對映函式 f : x->y,其中x是原始資料點的表達,目前最多使用向量表達形式。 y是資料點對映後的低維向量表達,通常y的維度小於x的維度(當然提高維度也是可以的)。f可能是顯式的或隱式的、線性的或非線性的。

       目前大部分降維演算法處理向量表達的資料,也有一些降維演算法處理高階張量表達的資料。之所以使用降維後的資料表示是因為在原始的高維空間中,包含有冗餘資訊以及噪音資訊,在實際應用例如影象識別中造成了誤差,降低了準確率;而通過降維,我們希望減少

冗餘資訊所造成的誤差,提高識別(或其他應用)的精度。又或者希望通過降維演算法來尋找資料內部的本質結構特徵。

       在很多演算法中,降維演算法成為了資料預處理的一部分,如PCA。事實上,有一些演算法如果沒有降維預處理,其實是很難得到很好的效果的。

對原始資料採取降維的原因通常有兩個:① 緩解“維度災難”  ② 對資料進行視覺化。

  降維的好壞沒有一個直接的標準(包括上面提到的重構誤差也只能作為一箇中性的指標)。通常通過對資料進行降維,然後用降維後的資料進行學習,再根據學習的效果選擇一個恰當的降維方式和一個合適的降維模型引數。 

sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False) 

一、關於引數

n_components:  

意義:PCA演算法中所要保留的主成分個數n,也即保留下來的特徵個數n

型別:int 或者 string,預設時預設為None,所有成分被保留。          

賦值為int,比如n_components=1,將把原始資料降到一個維度。          

賦值為string,比如n_components='mle',將自動選取特徵個數n,使得滿足所要求的方差百分比。

copy: 型別:bool,True或者False,預設時預設為True。

意義:表示是否在執行演算法時,將原始訓練資料複製一份。若為True,則執行PCA演算法後,原始訓練資料的值不會有任何改變,因為是在原始資料的副本上進行運算;若為False,則執行PCA演算法後,原始訓練資料的值會改,因為是在原始資料上進行降維計算。

whiten: 型別:bool,預設時預設為False ;     意義:白化。

二、PCA物件屬性

components_:返回具有最大方差的成分。

explained_variance_ratio_:返回 所保留的n個成分各自的方差百分比。 n_components_:返回所保留的成分個數n。

mean_

noise_variance_

三、PCA物件屬性

fit(X,y=None)

  • fit()可以說是scikit-learn中通用的方法,每個需要訓練的演算法都會有fit()方法,它其實就是演算法中的“訓練”這一步驟。因為PCA是無監督學習演算法,此處y自然等於None。
  • fit(X):表示用資料X來訓練PCA模型。
  • 函式返回值:呼叫fit方法的物件本身。比如pca.fit(X),表示用X對pca這個物件進行訓練。

fit_transform(X)

  • 用X來訓練PCA模型,同時返回降維後的資料。
  • newX=pca.fit_transform(X),newX就是降維後的資料。

inverse_transform()

  • 將降維後的資料轉換成原始資料,
  • X=pca.inverse_transform(newX)

transform(X)

  • 將資料X轉換成降維後的資料。當模型訓練好後,對於新輸入的資料,都可以用transform方法來降維。

此外,還有get_covariance()、get_precision()、get_params(deep=True)、score(X, y=None)等方法,以後用到再補充吧。

流程

擬合數據並降維——n_components對應要將的維度 

'''擬合數據'''
K=1 # 要降的維度
model = pca.PCA(n_components=K).fit(x_train)   # 擬合數據,n_components定義要降的維度
Z = model.transform(x_train)    # transform就會執行降維操作

資料恢復

model.components_會得到降維使用的U矩陣

'''資料恢復並作圖''' 
Ureduce = model.components_ # 得到降維用的

Ureduce x_rec = np.dot(Z,Ureduce) # 資料恢復

手寫數字識別

導包,使用SVM

datasets讀取資料

分割訓練和預測資料train_test_split(可以放多個要分割的資料)

繪製前100個圖片

建立SVC模型gamma =0.001 訓練資料

預測資料,視覺化

導包

import pandas as pd
from pandas import Series,DataFrame
import numpy as np

import matplotlib.pyplot as plt
%matplotlib inline

'''PCA'''
from sklearn.decomposition import PCA

'''SVC演算法'''
from sklearn.svm import SVC
'''使用GridSearchCV搜尋最優引數'''
from sklearn.model_selection import GridSearchCV

資料集

data = pd.read_csv('./data/digits.csv')
data.shape
Out:(42000, 785)
# 28*28=784

顯示資料

  • # 屬性的不同的,導致了圖片數字顯示不同
  • # 屬性差別導致,形狀差別
image = data.loc[3][1:].values.reshape(28,28)
plt.figure(figsize=(1,1))
plt.imshow(image)

# piexel0這一列對資料的分類,一點用都沒有
data['pixel0'].sum()
Out:0

data['pixel5'].sum()
Out:0

data['pixel783'].sum()
Out:0

降維

  • # 降維,資料784維,屬性
  • # 沒用資料屬性去掉784維------>100維:提取100個關鍵的屬性

白化的概念

- 白化是一種重要的預處理過程,其目的就是降低輸入資料的冗餘性,使得經過白化處理的輸入資料具有如下性質:

  • (i)特徵之間相關性較低;(ii)所有特徵具有相同的方差。

  • 白化處理分PCA白化和ZCA白化,PCA白化保證資料各維度的方差為1,而ZCA白化保證資料各維度的方差相同。

  • PCA白化可以用於降維也可以去相關性,而ZCA白化主要用於去相關性,且儘量使白化後的資料接近原始輸入資料。

- PCA白化和ZCA白化的區別

    PCA白化ZCA白化都降低了特徵之間相關性較低,同時使得所有特徵具有相同的方差。

  • PCA白化需要保證資料各維度的方差為1,ZCA白化只需保證方差相等。
  • PCA白化可進行降維也可以去相關性,而ZCA白化主要用於去相關性另外。
  • ZCA白化相比於PCA白化使得處理後的資料更加的接近原始資料。

特徵資料和目標資料

X = data.iloc[:,1:]
y = data['label']

降維操作

''' PCA(n_components=None【要降的維度】, copy=True, whiten=False
【(i)特徵之間相關性較低;(ii)所有特徵具有相同的方差。】, 
svd_solver='auto', tol=0.0, iterated_power='auto', random_state=None)'''

pca = PCA(n_components=100,whiten=True)
pca.fit(X)
Out: 
PCA(copy=True, iterated_power='auto', n_components=100, random_state=None,
  svd_solver='auto', tol=0.0, whiten=True)

X_pca = pca.transform(X)  # transform就會執行降維操作
# X_pca,使用這個資料效果更好
X_pca.shape
Out:(42000,100)

X_pca[0:5000].shape
OUt:
(5000, 100)

GridSearchCV 的引數說明:

1.estimator
選擇使用的分類器,並且傳入除需要確定最佳的引數之外的其他引數。
每一個分類器都需要一個scoring引數,或者score方法:
如estimator=RandomForestClassifier(
	min_samples_split=100,
	min_samples_leaf=20,
	max_depth=8,
	max_features='sqrt',
	random_state=10),
 
2.param_grid
需要最優化的引數的取值,值為字典或者列表,例如:
	param_grid =param_test1,
	param_test1 = {'n_estimators':range(10,71,10)}。
 
3. scoring=None
模型評價標準,預設None,這時需要使用score函式;或者如scoring='roc_auc',
根據所選模型不同,評價準則不同。字串(函式名),或是可呼叫物件,
需要其函式簽名形如:scorer(estimator, X, y);如果是None,則使用estimator的誤差估計函式。
 
4.n_jobs=1
n_jobs: 並行數,int:個數,-1:跟CPU核數一致, 1:預設值
 
5.cv=None  
交叉驗證引數,預設None,使用三折交叉驗證。指定fold數量,預設為3,也可以是yield產生訓練/測試資料的生成器。
 
6.verbose=0, scoring=None
verbose:日誌冗長度,int:冗長度,0:不輸出訓練過程,1:偶爾輸出,>1:對每個子模型都輸出。
 
7.pre_dispatch=‘2*n_jobs’
指定總共分發的並行任務數。當n_jobs大於1時,資料將在每個執行點進行復制,這可能導致OOM,
而設定pre_dispatch引數,則可以預先劃分總共的job數量,使資料最多被複制pre_dispatch次
 
8.return_train_score=’warn’
如果“False”,cv_results_屬性將不包括訓練分數。
 
9.refit :預設為True,程式將會以交叉驗證訓練集得到的最佳引數,重新對所有可用的訓練集與開發集進行,
作為最終用於效能評估的最佳模型引數。即在搜尋引數結束後,用最佳引數結果再次fit一遍全部資料集。
 
10.iid:預設True,為True時,預設為各個樣本fold概率分佈一致,誤差估計為所有樣本之和,而非各個fold的平均。
 
進行預測的常用方法和屬性
grid.fit():執行網格搜尋
grid_scores_:給出不同引數情況下的評價結果
best_params_:描述了已取得最佳結果的引數的組合
best_score_:成員提供優化過程期間觀察到的最好的評分
-------------------------------------------------------
param_test1 ={'n_estimators':range(10,71,10)}  
gsearch1= GridSearchCV(
		estimator =RandomForestClassifier(
			min_samples_split=100,  
                        min_samples_leaf=20,max_depth=8,
			max_features='sqrt',
			random_state=10),   
                param_grid =param_test1,
		scoring='roc_auc',
		cv=5)  
gsearch1.fit(X,y)  
gsearch1.grid_scores_, 
gsearch1.best_params_, 
gsearch1.best_score_  
 
'''
輸出結果如下:
([mean: 0.80681, std:0.02236, params: {'n_estimators': 10},
  mean: 0.81600, std: 0.03275, params:{'n_estimators': 20},
  mean: 0.81818, std: 0.03136, params:{'n_estimators': 30},
  mean: 0.81838, std: 0.03118, params:{'n_estimators': 40},
  mean: 0.82034, std: 0.03001, params:{'n_estimators': 50},
  mean: 0.82113, std: 0.02966, params:{'n_estimators': 60},
  mean: 0.81992, std: 0.02836, params:{'n_estimators': 70}],
{'n_estimators': 60},
0.8211334476626017)
'''
如果有transform,使用Pipeline簡化系統搭建流程,將transform與分類器串聯起來(Pipelineof transforms with a final estimator)
 
pipeline= Pipeline([("features", combined_features), ("svm", svm)])  
param_grid= dict(features__pca__n_components=[1, 2, 3],  
                  features__univ_select__k=[1,2],  
                  svm__C=[0.1, 1, 10])  
   
grid_search= GridSearchCV(pipeline, param_grid=param_grid, verbose=10)  
grid_search.fit(X,y)  
print(grid_search.best_estimator_)  
# 轉:https://blog.csdn.net/WxyangID/article/details/80397185

使用SVC演算法

'''C懲罰係數預設值是1  -->[0.1,0.5,1,2,3,5]
 gamma是kernel係數預設值是1/n_features = 0.01 -->[0.0001,0.001,0.01,0.05,0.1,0.5]
'''
svc = SVC()
# 定義引數取值
params = {'C':[1,3],'gamma':[0.001,0.05]}

'''GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1,
iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', 
error_score='raise', return_train_score='warn')'''

# 使用GridSearchCV網格搜尋出最優引數
gcv = GridSearchCV(svc,param_grid=params)

使用前5000個數據訓練,後500個數據做測試:

X_train = X_pca[0:5000]

X_test = X_pca[-500:]

y_train = y[:5000]

y_test = y[-500:]

使用gcv訓練資料,找出最優解

# 認為for遍歷引數,尋找最優的引數
gcv.fit(X_train,y_train)
Out:
GridSearchCV(cv=None, error_score='raise',
       estimator=SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False),
       fit_params=None, iid=True, n_jobs=1,
       param_grid={'C': [1, 3], 'gamma': [0.001, 0.05]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=0)

'''最優解:C=3,gamma=0.001'''
svc_best = gcv.best_estimator_
svc_best
Out:
SVC(C=3, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma=0.001, kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)

gcv.best_score_
Out: 0.9106

svc_best.score(X_test,y_test)
Out: 0.926

若不進行降維,速度慢,準確度低

# 如果不進行降維
X_train1 = X[:5000]
y_train1 = y[:5000]

X_test1 = X[-500:]
y_test1 = y[-500:]


print(time.time())
svc_best.fit(X_train1,y_train1)
print(time.time())
Out:
1532486494.0555701
1532486563.2417252

# 準確率,不會太高,非常低,不能接受
# 對資料處理,降維好處顯而易見
'''svc_best是使用已經經過網格搜尋出最優引數的svc模型'''
svc_best.score(X_test1,y_test1)
Out: 0.142