[TOC]
## 一、標準化的原因
* 通常情況下是為了消除量綱的影響。譬如一個百分制的變量與一個5分值的變量在一起怎么比較?只有通過數據標準化,都把它們標準到同一個標準時才具有可比性,一般標準化采用的是Z標準化,即均值為0,方差為1,當然也有其他標準化,比如0--1標準化等等,可根據自己的數據分布情況和模型來選擇
## 二、適用情況
* 看模型是否具有伸縮不變性。
* 不是所有的模型都一定需要標準化,有些模型對量綱不同的數據比較敏感,譬如SVM等。當各個維度進行不均勻伸縮后,最優解與原來不等價,這樣的模型,除非原始數據的分布范圍本來就不叫接近,否則必須進行標準化,以免模型參數被分布范圍較大或較小的數據主導。但是如果模型在各個維度進行不均勻伸縮后,最優解與原來等價,例如logistic regression等,對于這樣的模型,是否標準化理論上不會改變最優解。但是,由于實際求解往往使用迭代算法,如果目標函數的形狀太“扁”,迭代算法可能收斂得很慢甚至不收斂。所以對于具有伸縮不變性的模型,最好也進行數據標準化。
## 三、三種數據變換方法的含義與應用
* Rescaling(重縮放/歸一化):通常是指增加或者減少一個常數,然后乘以/除以一個常數,來改變數據的衡量單位。例如:將溫度的衡量單位從攝氏度轉化為華氏溫度。
* Normalizing(正則化):通常是指除以向量的范數。例如:將一個向量的歐氏長度等價于1 。在神經網絡中,“正則化”通常是指將向量的范圍重縮放至最小化或者一定范圍,使所有的元素都在[0,1]范圍內。通常用于文本分類或者文本聚類中。
* Standardizing(標準化):通常是為了消除不同屬性或樣方間的不齊性,使同一樣方內的不同屬性間或同一屬性在不同樣方內的方差減小。例如:如果一個向量包含高斯分布的隨機值,你可能會通過除以標準偏差來減少均值,然后獲得零均值單位方差的“標準正態”隨機變量。
* 那么問題是,當我們在訓練模型的時候,一定要對數據進行變換嗎?這得視情況而定。很多人對多層感知機有個誤解,認為輸入的數據必須在[0,1]這個范圍內。雖然標準化后在訓練模型效果會更好,但實際上并沒有這個要求。但是最好使輸入數據中心集中在0周圍,所以把數據縮放到[0,1]其實并不是一個好的選擇。
* 如果你的輸出激活函數的范圍是[0,1](sigmoid函數的值域),那你必須保證你的目標值也在這個范圍內。但通常請款下,我們會使輸出激活函數的范圍適應目標函數的分布,而不是讓你的數據來適應激活函數的范圍。
* 當我們使用激活函數的范圍為[0,1]時,有些人可能更喜歡把目標函數縮放到[0.1,0.9]這個范圍。我懷疑這種小技巧的之所以流行起來是因為反向傳播的標準化太慢了導致的。但用這種方法可能會使輸出的后驗概率值不對。如果你使用一個有效的訓練算法的話,完全不需要用這種小技巧,也沒有必要去避免溢出(overflow)。
## 四、具體方法及代碼
### 一)標準化
#### 1.1 scale----零均值單位方差
```
1 from sklearn import preprocessing
2 import numpy as np
3 #raw_data
4 X = np.array([[1., -1., 2.], [2., 0., 0.], [0., 1., -1.]])
5 X_scaled = preprocessing.scale(X)
6 #output
7 X_scaled = [[ 0. -1.22474487 1.33630621]
8 [ 1.22474487 0. -0.26726124]
9 [-1.22474487 1.22474487 -1.06904497]]
10 #scaled之后的數據零均值,單位方差
11 X_scaled.mean(axis=0) # column mean: array([ 0., 0., 0.])
12 X_scaled.std(axis=0) #column standard deviation: array([ 1., 1., 1.])
```
#### 1.2 StandardScaler----計算訓練集的平均值和標準差,以便測試數據集使用相同的變換
```
1 scaler = preprocessing.StandardScaler().fit(X)
2 #out:
3 StandardScaler(copy=True, with_mean=True, with_std=True)
4 scaler.mean_
5 #out:
6 array([ 1., 0. , 0.33333333])
7 scaler.std_
8 #out:
9 array([ 0.81649658, 0.81649658, 1.24721913])
10 #測試將該scaler用于輸入數據,變換之后得到的結果同上
11 scaler.transform(X)
12 #out:
13 array([[ 0., -1.22474487, 1.33630621], [ 1.22474487, 0. , -0.26726124], [-1.22474487,1.22474487, -1.06904497]])
14 scaler.transform([[-1., 1., 0.]])
15 #scale the new data, out:
16 array([[-2.44948974, 1.22474487, -0.26726124]])
```
> 注:1)若設置with\_mean=False 或者 with\_std=False,則不做centering 或者scaling處理。 ?
> 2)scale和StandardScaler可以用于回歸模型中的目標值處理。
### 二)歸一化----將數據特征縮放至某一范圍(scalingfeatures to a range)
* 另外一種標準化方法是將數據縮放至給定的最小值與最大值之間,通常是0與1之間,可用[MinMaxScaler](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MinMaxScaler.html#sklearn.preprocessing.MinMaxScaler)實現。或者將最大的絕對值縮放至單位大小,可用[MaxAbsScaler](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MaxAbsScaler.html#sklearn.preprocessing.MaxAbsScaler)實現。
* 使用這種標準化方法的原因是,有時數據集的標準差非常非常小,有時數據中有很多很多零(稀疏數據)需要保存住0元素。
#### 2.1 MinMaxScaler(最小最大值標準化)
```
公式:X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0)) ;
X_scaler = X_std/ (max - min) + min
```
```
1 #例子:將數據縮放至[0, 1]間
2 X_train = np.array([[1., -1., 2.], [2., 0., 0.], [0., 1., -1.]])
3 min_max_scaler = preprocessing.MinMaxScaler()
4 X_train_minmax = min_max_scaler.fit_transform(X_train)
5 #out:
6 array([[ 0.5 , 0. , 1. ],
7 [ 1. , 0.5 , 0.33333333],
8 [ 0. , 1. , 0. ]])
9 #將上述得到的scale參數應用至測試數據
10 X_test = np.array([[ -3., -1., 4.]])
11 X_test_minmax = min_max_scaler.transform(X_test) #out: array([[-1.5 , 0. , 1.66666667]])
12 #可以用以下方法查看scaler的屬性
13 min_max_scaler.scale_ #out: array([ 0.5 , 0.5, 0.33...])
14 min_max_scaler.min_ #out: array([ 0., 0.5, 0.33...])
```
#### 2.2 MaxAbsScaler(絕對值最大標準化)
* 與上述標準化方法相似,但是它通過除以最大值將訓練集縮放至[-1,1]。這意味著數據已經以0為中心或者是含有非常非常多0的稀疏數據。
```
1 X_train = np.array([[ 1., -1., 2.],
2 [ 2., 0., 0.],
3 [ 0., 1., -1.]])
4 max_abs_scaler = preprocessing.MaxAbsScaler()
5 X_train_maxabs = max_abs_scaler.fit_transform(X_train)
6 # out:
7 array([[ 0.5, -1., 1. ], [ 1. , 0. , 0. ], [ 0. , 1. , -0.5]])
8 X_test = np.array([[ -3., -1., 4.]])
9 X_test_maxabs = max_abs_scaler.transform(X_test)
10 #out:
11 array([[-1.5, -1. , 2. ]])
12 max_abs_scaler.scale_
13 #out:
14 array([ 2., 1., 2.])
```
* 其實在scale模塊里,也提供了這兩種方法: [`minmax_scale`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.minmax_scale.html#sklearn.preprocessing.minmax_scale)`和`[`maxabs_scale`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.maxabs_scale.html#sklearn.preprocessing.maxabs_scale)
#### 2.3 對稀疏數據進行標準化
- 對稀疏數據進行中心化會破壞稀疏數據的結構,這樣做沒什么意義。但是我們可以對稀疏數據的輸入進行標準化,尤其是特征在不同的標準時。[`MaxAbsScaler`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MaxAbsScaler.html#sklearn.preprocessing.MaxAbsScaler)和[`maxabs_scale`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.maxabs_scale.html#sklearn.preprocessing.maxabs_scale)是專門為稀疏數據設計的,也是常用的方法。但是[`scale`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.scale.html#sklearn.preprocessing.scale) 和 [`StandardScaler`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html#sklearn.preprocessing.StandardScaler)只接受scipy.sparse的矩陣作為輸入,并且必須設置with_centering=False。否則會出現 ValueError且破壞稀疏性,而且還會無意中分配更多的內存導致內存崩潰。[`RobustScaler`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.RobustScaler.html#sklearn.preprocessing.RobustScaler)不適用于稀疏數據的輸入,但是你可以用 transform 方法。
* scalers接受壓縮的稀疏行(Compressed Sparse Rows)和壓縮的稀疏列(Compressed Sparse Columns)的格式(具體參考**scipy.sparse.csr_matrix 和scipy.sparse.csc_matrix**)。其他的稀疏格式會被轉化成壓縮的稀疏行(Compressed Sparse Rows)格式。為了避免這種不必要的內存拷貝,推薦使用CSR或者CSC的格式。如果數據很小,可以在稀疏矩陣上運用toarray 方法。
#### 2.4 對離群點進行標準化
* 如果你的數據有離群點(上一篇我們提到過),對數據進行均差和方差的標準化效果并不好。這種情況你可以使用[`robust_scale`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.robust_scale.html#sklearn.preprocessing.robust_scale) 和 [`RobustScaler`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.RobustScaler.html#sklearn.preprocessing.RobustScaler) 作為替代。它們有對數據中心化和數據的縮放魯棒性更強的參數。
### 三)正則化
#### 3.1 L1、L2正則化
```
1 x=np.array([[1.,-1.,2.],
2 [2.,0.,0.],
3 [0.,1.,-1.]])
4 x_normalized=preprocessing.normalize(x,norm='l2')
5 print(x_normalized)
6
7 # 可以使用processing.Normalizer()類實現對訓練集和測試集的擬合和轉換
8 normalizer=preprocessing.Normalizer().fit(x)
9 print(normalizer)
10 normalizer.transform(x)
```
* 注:稀疏數據輸入:
[`normalize`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.normalize.html#sklearn.preprocessing.normalize)?和?[`Normalizer`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.Normalizer.html#sklearn.preprocessing.Normalizer)既接受稠密數據(dense array-like),也接受稀疏矩陣(from scipy.sparse)作為輸入。
稀疏數據需要轉換成壓縮的稀疏行(Compressed Sparse Rows)格式(詳見scipy.sparse.csr_matrix),為了避免不必要的內存拷貝,推薦使用CSR。
### 四)二值化
#### 4.1特征二值化
* 特征二值化是把數值特征轉化成布爾值的過程。這個方法對符合多變量伯努利分布的輸入數據進行預測概率參數很有效。詳細可以見這個例子[`sklearn.neural_network.BernoulliRBM`](http://scikit-learn.org/stable/modules/generated/sklearn.neural_network.BernoulliRBM.html#sklearn.neural_network.BernoulliRBM).
* 此外,在文本處理中也經常會遇到二值特征值(很可能是為了簡化概率推理),即使在實際中正則化后的詞頻或者TF-IDF的值通常只比未正則化的效果好一點點。
* 對于?[`Normalizer`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.Normalizer.html#sklearn.preprocessing.Normalizer)`,`[`Binarizer`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.Binarizer.html#sklearn.preprocessing.Binarizer)`工具類通常是在Pipeline階段(`[`sklearn.pipeline.Pipeline`](http://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline)`)的前期過程會用到。下面舉一個具體的例子:`
```
1 #input
2 X = [[ 1., -1., 2.],
3 [ 2., 0., 0.],
4 [ 0., 1., -1.]]
5 #binary
6 binarizer = preprocessing.Binarizer().fit(X) # fit does nothing
7 binarizer
8 Binarizer(copy=True, threshold=0.0)
9 #transform
10 binarizer.transform(X)
11 #out:
12 array([[ 1., 0., 1.],
13 [ 1., 0., 0.],
14 [ 0., 1., 0.]])
15
16 # 調整閾值
17 binarizer = preprocessing.Binarizer(threshold=1.1)
18 binarizer.transform(X)
19 #out:
20 array([[ 0., 0., 1.],
21 [ 1., 0., 0.],
22 [ 0., 0., 0.]])
```
* 注:稀疏數據輸入:
[`binarize`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.binarize.html#sklearn.preprocessing.binarize)`?和?`[`Binarizer`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.Binarizer.html#sklearn.preprocessing.Binarizer)`?既接受稠密數據(**dense array-like**),也接受稀疏矩陣(**from scipy.sparse**)作為輸入`
* 稀疏數據需要轉換成壓縮的稀疏行(Compressed Sparse Rows)格式(詳見scipy.sparse.csr\_matrix),為了避免不必要的內存拷貝,推薦使用CSR。
### 五)對類別特征進行編碼
* ?我們經常會遇到一些類別特征,這些特征不是離散型的數值,而是這樣的:\["男性","女性"\],\["來自歐洲","來自美國","來自亞洲"\],\["使用Firefox瀏覽器","使用Chrome瀏覽器","使用Safari瀏覽器","使用IE瀏覽器"\]等等。這種類型的特征可以被編碼為整型(int),如\["男性","來自美國","使用IE瀏覽器"\]可以表示成\[0,1,3\],\["女性","來自亞洲","使用Chrome瀏覽器"\]可以表示成\[1,2,1\]。這些整數式的表示不能直接作為sklearn的參數,因為我們需要的是連續型的輸入,而且我們通常是有序的翻譯這些特征,而不是所有的特征都是有序化的(譬如瀏覽器就是按人工排的序列)。
* ?將這些類別特征轉化成sklearn參數中可以使用的方法是:使用one-of-K或者one-hot編碼(獨熱編碼[`OneHotEncoder`](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html#sklearn.preprocessing.OneHotEncoder))。它可以把每一個有m種類別的特征轉化成m中二值特征。舉例如下:
```
1 enc = preprocessing.OneHotEncoder()
2 #input
3 enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
4 OneHotEncoder(categorical_features='all', dtype=<... 'float'>,handle_unknown='error', n_values='auto', sparse=True)
5 #transform
6 enc.transform([[0, 1, 3]]).toarray()
7 #out
8 array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])
```
* 默認情況下,特征的類別數量是從數據集里自動判斷出來的。當然,你也可以用n\_values這個參數。我們剛剛舉的例子中有兩種性別,三種地名和四種瀏覽器,當我們fit之后就可以將我們的數據轉化為數值了。從結果中來看,第一個數字代表性別(\[0,1\]代表男性,女性),第二個數字代表地名(\[0,1,2\]代表歐洲、美國、亞洲),最后一個數字代表瀏覽器(\[3,0,1,2\]代表四種瀏覽器)
* 此外,字典格式也可以編碼:?[Loading features from dicts](http://scikit-learn.org/stable/modules/feature_extraction.html#dict-feature-extraction)
* OneHotEncoder參數:*class?*`sklearn.preprocessing.``OneHotEncoder`(*n\_values='auto'*,?*categorical\_features='all'*,?*dtype=*,?*sparse=True*,?*handle\_unknown='error'*)
```
n\_values?: ‘auto’, int or array of ints
每個特征的數量
‘auto’ : 從訓練數據的范圍中得到
int : 所有特征的最大值(number)
array : 每個特征的最大值(number)
categorical\_features: “all” or array of indices or mask?:
確定哪些特征是類別特征
‘all’ (默認): 所有特征都是類別特征,意味著所有特征都要進行OneHot編碼
array of indices: 類別特征的數組索引
mask: n\_features 長度的數組,切dtype = bool
非類別型特征通常會放到矩陣的右邊
dtype : number type, default=np.float
輸出數據的類型
sparse?: boolean, default=True
設置True會返回稀疏矩陣,否則返回數組
handle\_unknown : str, ‘error’ or ‘ignore’
當一個不明類別特征出現在變換中時,報錯還是忽略
```
### 六)缺失值的插補
* 上篇我們講了五種方法來解決缺失值的問題,其實sklearn里也有一個工具[Imputer](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.Imputer.html#sklearn.preprocessing.Imputer)可以對缺失值進行插補。Imputer類可以對缺失值進行均值插補、中位數插補或者某行/列出現的頻率最高的值進行插補,也可以對不同的缺失值進行編碼。**并且支持稀疏矩陣。**
```
import numpy as np
from sklearn.preprocessing import Imputer
#用均值插補缺失值
imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
imp.fit([[1, 2], [np.nan, 3], [7, 6]])
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
X = [[np.nan, 2], [6, np.nan], [7, 6]]
print(imp.transform(X))
[[ 4. 2. ]
[ 6. 3.666...]
[ 7. 6. ]]
#對稀疏矩陣進行缺失值插補
import scipy.sparse as sp
X = sp.csc_matrix([[1, 2], [0, 3], [7, 6]])
imp = Imputer(missing_values=0, strategy='mean', axis=0)
imp.fit(X)
Imputer(axis=0, copy=True, missing_values=0, strategy='mean', verbose=0)
X_test = sp.csc_matrix([[0, 2], [6, 0], [7, 6]])
print(imp.transform(X_test))
[[ 4. 2. ]
[ 6. 3.666...]
[ 7. 6. ]]
```
* 在稀疏矩陣中,缺失值被編碼為0存儲為矩陣中,這種格式是適合于缺失值比非缺失值多得多的情況。此外,Imputer類也可以用于Pipeline中
* Imputor類的參數:*class?*`sklearn.preprocessing.``Imputer`(*missing\_values='NaN'*,?*strategy='mean'*,?*axis=0*,?*verbose=0*,?*copy=True*)
> **missing\_values**?: int或"NaN",默認NaN(String類型)
**strategy**?: string, 默認為mean,可選則mean、median、most\_frequent
**axis**?:int, 默認為0(axis = 0,對列進行插值;axis= 1,對行進行插值)
**verbose**?: int, 默認為0
**copy**?: boolean, 默認為True
True:會創建一個X的副本
False:在任何合適的地方都會進行插值。
但是以下四種情況,計算設置的copy = Fasle,也會創建一個副本:
1.X不是浮點型數組
2.X是稀疏矩陣,而且miss\_value = 0
3.axis= 0,X被編碼為CSR矩陣
4.axis= 1,X被編碼為CSC矩陣
* 舉個實例(在用隨機森林算法之前先用Imputer類進行處理):
```
import numpy as np
from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import Imputer
from sklearn.cross_validation import cross_val_score
rng = np.random.RandomState(0)
dataset = load_boston()
X_full, y_full = dataset.data, dataset.target
n_samples = X_full.shape[0]
n_features = X_full.shape[1]
# Estimate the score on the entire dataset, with no missing values
estimator = RandomForestRegressor(random_state=0, n_estimators=100)
score = cross_val_score(estimator, X_full, y_full).mean()
print("Score with the entire dataset = %.2f" % score)
# Add missing values in 75% of the lines
missing_rate = 0.75
n_missing_samples = np.floor(n_samples * missing_rate)
missing_samples = np.hstack((np.zeros(n_samples - n_missing_samples,
dtype=np.bool),
np.ones(n_missing_samples,
dtype=np.bool)))
rng.shuffle(missing_samples)
missing_features = rng.randint(0, n_features, n_missing_samples)
# Estimate the score without the lines containing missing values
X_filtered = X_full[~missing_samples, :]
y_filtered = y_full[~missing_samples]
estimator = RandomForestRegressor(random_state=0, n_estimators=100)
score = cross_val_score(estimator, X_filtered, y_filtered).mean()
print("Score without the samples containing missing values = %.2f" % score)
# Estimate the score after imputation of the missing values
X_missing = X_full.copy()
X_missing[np.where(missing_samples)[0], missing_features] = 0
y_missing = y_full.copy()
estimator = Pipeline([("imputer", Imputer(missing_values=0,
strategy="mean",
axis=0)),
("forest", RandomForestRegressor(random_state=0,
n_estimators=100))])
score = cross_val_score(estimator, X_missing, y_missing).mean()
print("Score after imputation of the missing values = %.2f" % score)
```
* 結果:
```
Score with the entire dataset = 0.56
Score without the samples containing missing values = 0.48
Score after imputation of the missing values = 0.55
```
### 七)生成多項式特征?
* 在輸入數據中增加非線性特征可以有效的提高模型的復雜度。簡單且常用的方法就是使用多項式特征(polynomial features),可以得到特征的高階交叉項:
```
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
X = np.arange(6).reshape(3, 2)
X
array([[0, 1],
[2, 3],
[4, 5]])
poly = PolynomialFeatures(2)
poly.fit_transform(X)
array([[ 1., 0., 1., 0., 0., 1.],
[ 1., 2., 3., 4., 6., 9.],
[ 1., 4., 5., 16., 20., 25.]])
```
* 然而有時候我們只需要特征的交叉項,可以設置interaction\_only=True來得到:
```
X = np.arange(9).reshape(3, 3)
X
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
poly = PolynomialFeatures(degree=3, interaction_only=True)
poly.fit_transform(X)
array([[ 1., 0., 1., 2., 0., 0., 2., 0.],
[ 1., 3., 4., 5., 12., 15., 20., 60.],
[ 1., 6., 7., 8., 42., 48., 56., 336.]])
```
* ?這個方法可能大家在工作中比較少見,但世界上它經常用于核方法中,如選擇多項式核時?(?[`sklearn.svm.SVC`](http://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC "sklearn.svm.SVC"),?[`sklearn.decomposition.KernelPCA`](http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.KernelPCA.html#sklearn.decomposition.KernelPCA "sklearn.decomposition.KernelPCA"))
### 八)自定義轉換
* 如果以上的方法覺得都不夠,譬如你想用對數據取對數,可以自己用?`[FunctionTransformer](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.FunctionTransformer.html#sklearn.preprocessing.FunctionTransformer "sklearn.preprocessing.FunctionTransformer")自定義一個轉化器,并且可以在Pipeline中使用`
```
import numpy as np
from sklearn.preprocessing import FunctionTransformer
transformer = FunctionTransformer(np.log1p)#括號內的就是自定義函數
X = np.array([[0, 1], [2, 3]])
transformer.transform(X)
array([[ 0. , 0.69314718],
[ 1.09861229, 1.38629436]])
```
* 告訴你怎么用:
* 如果你在做一個分類任務時,發現第一主成分與這個不相關,你可以用[FunctionTransformer](http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.FunctionTransformer.html#sklearn.preprocessing.FunctionTransformer "sklearn.preprocessing.FunctionTransformer")把第一列除去,剩下的列用PCA:
```
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cross_validation import train_test_split
from sklearn.decomposition import PCA
from sklearn.pipeline import make_pipeline
# from sklearn.preprocessing import FunctionTransformer
# 如果報錯ImportError: cannot import name FunctionTransformer,可以使用下面的語句
from sklearn.preprocessing import *
def _generate_vector(shift=0.5, noise=15):
return np.arange(1000) + (np.random.rand(1000) - shift) * noise
def generate_dataset():
"""
This dataset is two lines with a slope ~ 1, where one has
a y offset of ~100
"""
return np.vstack((
np.vstack((
_generate_vector(),
_generate_vector() + 100,
)).T,
np.vstack((
_generate_vector(),
_generate_vector(),
)).T,
)), np.hstack((np.zeros(1000), np.ones(1000)))
def all_but_first_column(X):
return X[:, 1:]
def drop_first_component(X, y):
"""
Create a pipeline with PCA and the column selector and use it to
transform the dataset.
"""
pipeline = make_pipeline(
PCA(), FunctionTransformer(all_but_first_column),
)
X_train, X_test, y_train, y_test = train_test_split(X, y)
pipeline.fit(X_train, y_train)
return pipeline.transform(X_test), y_test
if __name__ == '__main__':
X, y = generate_dataset()
plt.scatter(X[:, 0], X[:, 1], c=y, s=50)
plt.show()
X_transformed, y_transformed = drop_first_component(*generate_dataset())
plt.scatter(
X_transformed[:, 0],
np.zeros(len(X_transformed)),
c=y_transformed,
s=50,
)
plt.show()
```
* 結果:
