天天看點

從sklearn.preprocessing, sklearn.feature_selection學習特征工程之預處理

特征工程思維導圖如下圖。 本文借助sklearn介紹其中的預處理部分

從sklearn.preprocessing, sklearn.feature_selection學習特征工程之預處理

二 單特征預處理

       <1> 标準化   Standardization   或者叫 mean removal and variance scaling(平均值移除、方差縮放)

             說明1: 标準化其實就是幹兩件事:“transform the data to center” ,即使資料平均值為0;

                                                               “scale it by dividing non-constant features by their standard deviation”,即标準差為1

              (1)  sklearn 提供了scale做資料标準化:            

>>> from sklearn import preprocessing
>>> import numpy as np
>>> X = np.array([[1., -1., 2.],
...               [2.,  0., 0.],
...               [0.,  1., -1.]])
>>> X_scaled = preprocessing.scale(X)
>>> X_scaled
array([[ 0.        , -1.22474487,  1.33630621],
       [ 1.22474487,  0.        , -0.26726124],
       [-1.22474487,  1.22474487, -1.06904497]])
>>> X_scaled.mean(axis=0)
array([ 0.,  0.,  0.])
>>> X_scaled.std(axis=0)
array([ 1.,  1.,  1.])
           

                 preprocessing 提供了另一個實用的類StandardScaler,它的fit函數解析訓練資料(包括值和矩陣格式),transform則對

                 資料執行standardization過程。 在訓練資料上使用的StandardScalar對象可以再使用在測試資料上

>>> scaler = preprocessing.StandardScaler().fit(X)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)
>>> scaler.mean_
array([ 1.        ,  0.        ,  0.33333333])
>>> scaler.scale_
array([ 0.81649658,  0.81649658,  1.24721913])
>>> scaler.transform(X)
array([[ 0.        , -1.22474487,  1.33630621],
       [ 1.22474487,  0.        , -0.26726124],
       [-1.22474487,  1.22474487, -1.06904497]])
>>> X_test = np.array([[-1., 1., 0.]])
>>> scaler.transform(X_test)
array([[-2.44948974,  1.22474487, -0.26726124]])
           

                     StandardScaler的構造函數中可以關閉with_mean和with_std

                (2) 縮放至一定範圍

                 先介紹MinMaxScaler的使用, 使用max - min作為分母

>>> X_train = np.array([[1., -1., 2.],
...                     [2., 0., 0.],
...                     [0., 1., -1]])
>>> min_max_scaler = preprocessing.MinMaxScaler()
>>> X_train_minmax = min_max_scaler.fit_transform(X_train)
>>> X_train_minmax
array([[ 0.5       ,  0.        ,  1.        ],
       [ 1.        ,  0.5       ,  0.33333333],
       [ 0.        ,  1.        ,  0.        ]])
>>> X_test = np.array([[ -3., -1.,  4.]])
>>> X_test_minmax = min_max_scaler.transform(X_test)
>>> X_test_minmax
array([[-1.5       ,  0.        ,  1.66666667]])
           

                   在介紹MaxAbsScaler, 将最大的絕對值作為分母

>>> max_abs_scaler = preprocessing.MaxAbsScaler()
>>> X_train_maxabs = max_abs_scaler.fit_transform(X_train)
>>> X_train_maxabs
array([[ 0.5, -1. ,  1. ],
       [ 1. ,  0. ,  0. ],
       [ 0. ,  1. , -0.5]])
>>> X_test = np.array([[ -3., -1.,  4.]])
>>> X_test_maxabs = max_abs_scaler.transform(X_test)
>>> X_test_maxabs
array([[-1.5, -1. ,  2. ]])
>>> max_abs_scaler.scale_
array([ 2.,  1.,  2.])
           

              如果不想建立scaler對象、不需要後面的test data上使用,可以使用 minmax_scale和maxabs_scale方法

          <2>  正則化 Normalization   (跟以前了解的正則化概念不同)

          正則化的過程是将每個樣本縮放到機關範數。對于後面要通過點積或其他核方法計算兩個樣本之間相似性的情況,

      該正則化十分有用。

          Normalization主要思想是對每個樣本計算p-範數(例如l1-範數,l2-範數等),然後樣本的每個元素除以該範數。則

      執行正則化的樣本的p-範數變為1。    p-範數的公式: ||X||p = (|x1|^p + |x2|^p + .... + |xn|^p)^1/p

         該方法主要用于文本分類和聚類,例如兩個tf-idf向量的l2正則化進行點積就得到兩個向量的餘弦相似性

>>> X_normalized
array([[ 0.40824829, -0.40824829,  0.81649658],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.        ,  0.70710678, -0.70710678]])
           

           同樣提供了類:

>>> normalizer = preprocessing.Normalizer().fit(X)
>>> normalizer
Normalizer(copy=True, norm='l2')
>>> normalizer.transform(X)
array([[ 0.40824829, -0.40824829,  0.81649658],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.        ,  0.70710678, -0.70710678]])
>>> normalizer.transform([[-1.,  1., 0.]])
array([[-0.70710678,  0.70710678,  0.        ]])
           

         <3> Binarization  二值化

                      特征二值化是指依據一個門檻值,将大于門檻值的指派為1, 小于等于門檻值的指派為0.

>>> X
array([[ 1., -1.,  2.],
       [ 2.,  0.,  0.],
       [ 0.,  1., -1.]])
>>> binarizer = preprocessing.Binarizer().fit(X)
>>> binarizer
Binarizer(copy=True, threshold=0.0)
>>> binarizer.transform(X)
array([[ 1.,  0.,  1.],
       [ 1.,  0.,  0.],
       [ 0.,  1.,  0.]])
>>> binarizer2 = preprocessing.Binarizer(threshold=1.1)
>>> binarizer2.transform(X)
array([[ 0.,  0.,  1.],
       [ 1.,  0.,  0.],
       [ 0.,  0.,  0.]])
           

           <4> 類别型特征編碼

           可以使用oneHot encoding 将類别型特征進行編碼。

>>> enc = preprocessing.OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])  # 第一個特征有2個類别,第二個特征有3個類别,第三個特征有4類别
OneHotEncoder(categorical_features='all', dtype=<type 'numpy.float64'>,
       handle_unknown='error', n_values='auto', sparse=True)
>>> enc.transform([[0, 0, 0]]).toarray()
array([[ 1.,  0.,  1.,  0.,  0.,  1.,  0.,  0.,  0.]])  # 第一個特征占據前兩位,第二個特征占據厚3個位置,第三個特征占最後4個
>>> enc.transform([[1, 0, 0]]).toarray()
array([[ 0.,  1.,  1.,  0.,  0.,  1.,  0.,  0.,  0.]])
>>> enc.transform([[0, 1, 0]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  1.,  0.,  0.,  0.]])
>>> enc.transform([[0, 2, 0]]).toarray()
array([[ 1.,  0.,  0.,  0.,  1.,  1.,  0.,  0.,  0.]])
>>> enc.transform([[0, 0, 1]]).toarray()
array([[ 1.,  0.,  1.,  0.,  0.,  0.,  1.,  0.,  0.]])
>>> enc.transform([[0, 0, 2]]).toarray()
array([[ 1.,  0.,  1.,  0.,  0.,  0.,  0.,  1.,  0.]])
>>> enc.transform([[0, 0, 3]]).toarray()
array([[ 1.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  1.]])
           

      如果訓練資料中的類别不全,則可以指定每個特征的類别數量

>>> enc = preprocessing.OneHotEncoder(n_values=[2,3,4])  #指定
>>> enc.fit([[1, 2, 3], [0, 2, 0]])
OneHotEncoder(categorical_features='all', dtype=<type 'numpy.float64'>,
       handle_unknown='error', n_values=[2, 3, 4], sparse=True)
>>> enc.transform([[1, 2, 0]]).toarray()
array([[ 0.,  1.,  0.,  0.,  1.,  1.,  0.,  0.,  0.]])
>>> enc.transform([[1, 0, 0]]).toarray()
array([[ 0.,  1.,  1.,  0.,  0.,  1.,  0.,  0.,  0.]])
>>> enc.transform([[1, 1, 0]]).toarray()
array([[ 0.,  1.,  0.,  1.,  0.,  1.,  0.,  0.,  0.]])
           

             <5> 預設值計算 ---------Imputer

>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
>>> imp
Imputer(add_indicator_features=False, axis=0, copy=True, missing_values='NaN',
    strategy='mean', verbose=0)
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])   #第一維的平均值為4, 第二維的平均值為3.667
Imputer(add_indicator_features=False, axis=0, copy=True, missing_values='NaN',
    strategy='mean', verbose=0)
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> imp.transform(X)
array([[ 4.        ,  2.        ],
       [ 6.        ,  3.66666667],
       [ 7.        ,  6.        ]])
           

           <6> 特征的多項式變換

                多項式變換會将每個樣本資料擴充為原本元素的多項式項,例如

                (X1, X2) 經過二項式變換,變為(1, X1, X2, X1^2, X1X2, X2^2)

>>> X = np.arange(6).reshape(3,2)
>>> X
array([[0, 1],
       [2, 3],
       [4, 5]])
>>> poly = preprocessing.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.]])
           

               還可以指定隻保留互動項:

                (X1, X2) 經過二項式變換隻保留互動項,變為(1, X1, X2,  X1X2)

>>> X
array([[0, 1],
       [2, 3],
       [4, 5]])
>>> poly2 = preprocessing.PolynomialFeatures(degree=2, interaction_only=True)
>>> poly2.fit_transform(X)
array([[  1.,   0.,   1.,   0.],
       [  1.,   2.,   3.,   6.],
       [  1.,   4.,   5.,  20.]])
           

           <7> 自定義變換

            可是使用FunctionTransformer指定一個子選擇的變換方法

>>> from numpy import log1p  # log1p(x) = log(1 + x)
>>> from sklearn.preprocessing import FunctionTransformer
>>> trans = FunctionTransformer(log1p)
>>> X = np.array([[0,1], [2, 3]])
>>> trans.transform(X)
array([[ 0.        ,  0.69314718],
       [ 1.09861229,  1.38629436]])
           

三 特征選擇

     <1> Filter 過濾法   ---------多使用于線性的模型

             1.1 方差選擇法

                   删除元素方差小于等于門檻值的特征                    例如,假設data中每個特征是二項分布(n次伯努利分布),而伯努利分布的方差(variance)Var = p(1-p)                

>>> from sklearn.feature_selection import VarianceThreshold
>>> X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
>>> sel = VarianceThreshold(threshold=(.8 * (1 - .8)))   #
>>> sel.fit_transform(X)
array([[0, 1],
       [1, 0],
       [0, 0],
       [1, 1],
       [1, 0],
       [1, 1]])
           

              1.2 Univariate feature selection------ 單變量特征選擇

                  1.2.1 SelectKBest  ------保留k個最好的特征。   打分方法,例如卡方驗證

                   1.2.2 SelectPercentile------- 保留一定比例            

>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import chi2
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
>>> X_new.shape
(150, 2)
           

     <2> Wrapper --- 包裹法

           把特征選擇看做一個特征子集搜尋問題,篩選各種特征子集,用模型評估效果。            介紹RFE--- recursive feature elemination, 遞歸消除特征法, 每輪訓練,消除權值小的一定比例的特征,在基于新特征訓練,如果滿足                期望要求,繼續消除,以此遞歸,直到模型效果低于預期值。以LR為例,過程如下:                1. 使用全特征跑一個模型                2.根據線性模型的系數(展現相關性),删掉5%-10%的弱特征,觀察準确率/auc變化                3. 逐漸進行,知道準确率/auc出現大的下滑停止              class 

sklearn.feature_selection.

RFE

(estimator, n_features_to_select=None, step=1, verbose=0)            n_featuers_to_select ------保留的特征個數, 不指定則保留一半            step-----每次要消除的特征。 如果>1, 表示每次删除的個數; 如果[0,1]之間,表示每次删除的比例

>>> from sklearn.feature_selection import RFE
>>> from sklearn.linear_model import LogisticRegression
>>> rfe = RFE(LogisticRegression(), n_features_to_select=1, step=1)
>>> rfe.fit(X, y)
           

    <3> Embedded -----嵌入法,  SelectFromModel

         class 

sklearn.feature_selection.

SelectFromModel

(estimator, threshold=None, prefit=False)

             estimator ----- 用來選擇特征的模型              threshold ----- 門檻值。  保留大于門檻值的特征。如果沒有指定,且estimator有penalty=l1或者                                      estimator為Lasso, 預設門檻值為1e-1, 否則預設值為平均值               prefit  --------是否需要先fit的模型

         (1) 基于L1正則化的特征選擇方法

        先了解L1正則化:http://blog.csdn.net/leiting_imecas/article/details/56351806          L1正則化可以用在維數很大時做特征選擇.          SelectFromModel其實就是先用一個模型(通常選擇線性模型)跑一下,把特征選擇出來

>>> from sklearn.svm import LinearSVC
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X,y)
>>> model = SelectFromModel(lsvc, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 3)
           

         sklearn說明文檔上說,選擇特征的模型的選擇問題:          linear_model.Lasso --------用于regression;           linear_model.LogisticRegression 和svm.LinearSVC ----------用于classification

        (2)基于樹的特征選擇            基于樹的模型可以用來計算特征的重要性,這樣也可以用來去除關聯性小的特征             

>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> iris = load_iris()
>>> X, y = iris.data, iris.target
>>> X.shape
(150, 4)
>>> clf = ExtraTreesClassifier()
>>> clf = clf.fit(X,y)
>>> clf.feature_importances_
array([ 0.05517225,  0.06978394,  0.52250383,  0.35253998])  #特征重要性
>>> model = SelectFromModel(clf, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 2)
           

[source]                 

繼續閱讀