1. 程式人生 > >結合sklearn進行特徵工程

結合sklearn進行特徵工程

1 前言

該篇部落格主要涉及到sklearn.feature_selection 以及其他相關模型,主要介紹瞭如何利用sklearn進行特徵工程,特徵工程在機器學習中佔有工程師的大部分精力,目前也有很多成熟的方法和理論,但是結合實際業務背景選擇特徵仍然是提升模型效能的關鍵點。sklearn.feature_selection是一個強大的特徵處理工具包,磨刀不誤砍柴工,熟練使用工具是重中之重!以下是特徵工程的概要圖。

特徵工程

2 資料預處理

  1. 不屬於同一量綱:即特徵的規格不一樣,不能夠放在一起比較。無量綱化可以解決這一問題。
  2. 缺失值處理:包括缺失值刪除及補充。
from sklearn.datasets import
load_iris #匯入IRIS資料集 iris = load_iris() #特徵矩陣 dataset = iris.data #目標向量 labels = iris.target print "特徵矩陣\n",dataset[:5,:] print '標籤\n',set(labels)
特徵矩陣
[[ 5.1  3.5  1.4  0.2]
 [ 4.9  3.   1.4  0.2]
 [ 4.7  3.2  1.3  0.2]
 [ 4.6  3.1  1.5  0.2]
 [ 5.   3.6  1.4  0.2]]
標籤
set([0, 1, 2])

2.1 資料無量綱化

無量綱化使不同規格的資料轉換到同一規格。常見的無量綱化方法有標準化和區間縮放法。標準化的前提是特徵值服從正態分佈,標準化後,其轉換成標準正態分佈。區間縮放法利用了邊界值資訊,將特徵的取值區間縮放到某個特定的範圍,例如[0, 1]等。

2.1.1 標準化

標準化需要計算每個特徵的均值和標準差,公式表達為:
x=xX¯S

使用preproccessing庫的StandardScaler類對資料進行標準化的程式碼如下:
標準化之後的資料範圍在[-1,1]之間

from sklearn.preprocessing import StandardScaler

#標準化,返回值為標準化後的資料,矩陣形式,下面只顯示了前10行資料
StandardScaler().fit_transform(dataset)[:10,:]
array([[-0.90068117,  1.03205722, -1.3412724 , -1.31297673],
       [-1.14301691, -0.1249576 , -1.3412724 , -1.31297673],
       [-1.38535265,  0.33784833, -1.39813811, -1.31297673],
       [-1.50652052,  0.10644536, -1.2844067 , -1.31297673],
       [-1.02184904,  1.26346019, -1.3412724 , -1.31297673],
       [-0.53717756,  1.95766909, -1.17067529, -1.05003079],
       [-1.50652052,  0.80065426, -1.3412724 , -1.18150376],
       [-1.02184904,  0.80065426, -1.2844067 , -1.31297673],
       [-1.74885626, -0.35636057, -1.3412724 , -1.31297673],
       [-1.14301691,  0.10644536, -1.2844067 , -1.4444497 ]])

2.1.2 歸一化處理

標準化與歸一化的區別
簡單來說,
標準化是依照特徵矩陣(每一列是用同一個特徵的不同取值)的列處理資料,其通過求z-score的方法,將樣本的每個特徵的值轉換到同一量綱下。
歸一化是依照特徵矩陣(每一行是不同特徵的取值)的行處理資料,其目的在於樣本向量在點乘運算或其他核函式計算相似性時,擁有統一的標準,也就是說都轉化為“單位向量”。

規則為L2範數的歸一化公式如下:
x=xj=1mx2j

使用preproccessing庫的Normalizer類對資料進行歸一化的程式碼如下:

from sklearn.preprocessing import Normalizer

#歸一化,返回值為歸一化後的資料的符號與原資料符號相同
Normalizer().fit_transform(dataset)[:10,:]
array([[ 0.80377277,  0.55160877,  0.22064351,  0.0315205 ],
       [ 0.82813287,  0.50702013,  0.23660939,  0.03380134],
       [ 0.80533308,  0.54831188,  0.2227517 ,  0.03426949],
       [ 0.80003025,  0.53915082,  0.26087943,  0.03478392],
       [ 0.790965  ,  0.5694948 ,  0.2214702 ,  0.0316386 ],
       [ 0.78417499,  0.5663486 ,  0.2468699 ,  0.05808704],
       [ 0.78010936,  0.57660257,  0.23742459,  0.0508767 ],
       [ 0.80218492,  0.54548574,  0.24065548,  0.0320874 ],
       [ 0.80642366,  0.5315065 ,  0.25658935,  0.03665562],
       [ 0.81803119,  0.51752994,  0.25041771,  0.01669451]])

2.1.3 區間縮放法

區間縮放法的思路有多種,常見的一種為利用兩個最值進行縮放,公式表達為:
x=xMinMaxMin

使用preproccessing庫的MinMaxScaler類對資料進行區間縮放的程式碼如下:區間縮放之後資料範圍在[0,1]之間

from sklearn.preprocessing import MinMaxScaler

#區間縮放,返回值為縮放到[0, 1]區間的資料
MinMaxScaler().fit_transform(dataset)[:10,:]
array([[ 0.22222222,  0.625     ,  0.06779661,  0.04166667],
       [ 0.16666667,  0.41666667,  0.06779661,  0.04166667],
       [ 0.11111111,  0.5       ,  0.05084746,  0.04166667],
       [ 0.08333333,  0.45833333,  0.08474576,  0.04166667],
       [ 0.19444444,  0.66666667,  0.06779661,  0.04166667],
       [ 0.30555556,  0.79166667,  0.11864407,  0.125     ],
       [ 0.08333333,  0.58333333,  0.06779661,  0.08333333],
       [ 0.19444444,  0.58333333,  0.08474576,  0.04166667],
       [ 0.02777778,  0.375     ,  0.06779661,  0.04166667],
       [ 0.16666667,  0.45833333,  0.08474576,  0.        ]])

2.2 缺失值處理

  1. 直接除去含有缺失值的樣本點
  2. 缺失值填補(其中sklearn、numpy、pandas等python工具包都有相應處理方法),在本次部落格中,只介紹sklearn工具包中的處理方法(imputer類),numpy和pandas會在其他部落格中給出。

由於IRIS資料包中並沒有缺失值,這裡會給出人工資料集的測試用例,處理缺失值的一般步驟如下所示:
1. 使用字串’nan’來代替資料集中的缺失值;
2. 將該資料集轉換為浮點型便可以得到包含np.nan的資料集;
3. 使用sklearn.preprocessing.Imputer類來處理使用np.nan對缺失值處理過的資料集。

import numpy as np
from sklearn.preprocessing import Imputer

#含有空格的資料
tem='1,2,3, ,3,4,5,6,7,8, ,9'
print tem

#替換空格字元
tem = tem.replace(' ','nan').split(',')
print tem
#將資料轉換成浮點型矩陣形式
x = np.array(tem,dtype = float).reshape((4,3))
print x
1,2,3, ,3,4,5,6,7,8, ,9
['1', '2', '3', 'nan', '3', '4', '5', '6', '7', '8', 'nan', '9']
[[  1.   2.   3.]
 [ nan   3.   4.]
 [  5.   6.   7.]
 [  8.  nan   9.]]
Imputer().fit_transform(x)
array([[ 1.        ,  2.        ,  3.        ],
       [ 4.66666667,  3.        ,  4.        ],
       [ 5.        ,  6.        ,  7.        ],
       [ 8.        ,  3.66666667,  9.        ]])

Imputer()的引數有:
1. missing_values:預設是((default=”NaN”))
2. strategy :string字元格式, optional (default=”mean”),一般有mean(均值),median(中位數),most_frequent(眾數)
3. axis:軸向,預設是(列向,axis =0),行是(axis=1)
可通過help指令顯示對Imputer的解釋

help(Imputer())

3 特徵構建

特徵構建包括以下內容:
1. 基於統計方法構造統計量
2. 對某些連續定量特徵進行離散化,以便去除冗餘資訊
3. 對定性特徵進行啞編碼,將其轉換成定量特徵
4. 特徵交叉

3.1 基於統計方法的構造統計量

該方法更多的是針對時間序列資料,例如,一段時間的廣告點選量的單位時間均值,一段時間,某個使用者對某個商品的瀏覽總數等。

3.2 對某些連續定量特徵離散化,以便去除冗餘資訊

3.2.1 對連續定量資料二值化

定量特徵二值化的核心在於設定一個閾值,大於閾值的賦值為1,小於等於閾值的賦值為0,公式表達如下:

x={1,x>threshold0,xthreshold

使用preproccessing庫的Binarizer類對資料進行二值化的程式碼如下:

from sklearn.preprocessing import Binarizer

#二值化,閾值設定為3,返回值為二值化後的資料
Binarizer(threshold = 3).fit_transform(dataset)[:10,:]
array([[ 1.,  1.,  0.,  0.],
       [ 1.,  0.,  0.,  0.],
       [ 1.,  1.,  0.,  0.],
       [ 1.,  1.,  0.,  0.],
       [ 1.,  1.,  0.,  0.],
       [ 1.,  1.,  0.,  0.],
       [ 1.,  1.,  0.,  0.],
       [ 1.,  1.,  0.,  0.],
       [ 1.,  0.,  0.,  0.],
       [ 1.,  1.,  0.,  0.]])

3.3 定性特徵啞編碼

特徵更多的時候是分類特徵,而不是連續的數值特徵。

比如一個人的特徵可以是[“male”, “female”], [“from Europe”, “from US”, “from Asia”], [“uses Firefox”, “uses Chrome”, “uses Safari”, “uses Internet Explorer”]。 這樣的特徵可以高效的編碼成整數,

例如 [“male”, “from US”, “uses Internet Explorer”]可以表示成[0, 1, 3],

[“female”, “from Asia”, “uses Chrome”]就是[1, 2, 1]。

這個的整數特徵表示並不能在scikit-learn的估計器中直接使用,因為這樣的連續輸入,估計器會認為類別之間是有序的,但實際卻是無序的。(例如:瀏覽器的類別資料則是任意排序的)。

一個將分類特徵轉換成scikit-learn估計器可用特徵的可選方法是使用one-of-K或者one-hot編碼,該方法是:class:OneHotEncoder的一個實現。該方法將每個類別特徵的 “m” 可能值轉換成”m”個二進位制特徵值,當然只有一個是啟用值。

from sklearn.preprocessing import OneHotEncoder
array = np.array([[0.1,0,3],[1,1,0],[0.7,2,1],[1,0,2]])
print array
print OneHotEncoder().fit_transform(array).toarray()
[[ 0.1  0.   3. ]
 [ 1.   1.   0. ]
 [ 0.7  2.   1. ]
 [ 1.   0.   2. ]]
[[ 1.  0.  1.  0.  0.  0.  0.  0.  1.]
 [ 0.  1.  0.  1.  0.  1.  0.  0.  0.]
 [ 1.  0.  0.  0.  1.  0.  1.  0.  0.]
 [ 0.  1.  1.  0.  0.  0.  0.  1.  0.]]
help(OneHotEncoder)

注意
1. 該編碼方法輸入矩陣的資料應為浮點型會整型,當為浮點型時,會自動轉為整型,直接保留整數位資料
2. 在矩陣array中,共有4行3列,假設每一列對應一個特徵,則第一列有兩個可能取值(屬性):0,1;第二列有三個可能取值:0,1,2;第三列可能取值:0,1,2,3;這樣一來,第一列(第一個特徵)可以用2位的二進位制碼來表示,第二列可以用3位二進位制碼來表示,第四列用4位二進位制碼來表示;因此會產生2+3+4=9列,從結果中可以看出第一列第一位0.1=1,0(二進位制),第二列第一位0=1,0,0,第三列第一位3=0,0,0,1
3. 從結果中還可以看出,編碼之前會對每一列的屬性值進行排序,屬性值對應的編碼值,第一位為最小屬性值,最後一位為最高屬性值。

3.4 特徵交叉

交叉從理論上而言是為了引入特徵之間的互動,也即為了引入非線性性。舉個簡單的例子,在特徵為性別的屬性值為對不同種類廣告的CTR(廣告點選率),當然還有其他方式,包括CTR與年齡,CTR與地域,下面介紹一種多項式特徵構建方法

很多情況下,多項式特徵是通過考慮輸入資料中的非線性特徵來增加模型的複雜性,它能捕捉到特徵中高階和相互作用的項。 :class:PolynomialFeatures類中可以實現該功能,其程式碼實現如下所示:

from sklearn.preprocessing import PolynomialFeatures
x =  np.arange(6).reshape(3,2)
print x
[[0 1]
 [2 3]
 [4 5]]
poly = PolynomialFeatures()#預設輸入兩個引數
help(poly)
poly.fit_transform(x)
array([[  1.,   0.,   1.,   0.,   0.,   1.],
       [  1.,   2.,   3.,   4.,   6.,   9.],
       [  1.,   4.,   5.,  16.,  20.,  25.]])

上述執行過程是在input_feature = (x1,x2),output_feature = (1,x1,x2,x21,x22,x1x2),引數degree =2,interaction_only = False

x = np.arange(9).reshape(3, 3)
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.]])

上述執行過程是在input_feature = (x1,x2,x3),output_feature = (1,x1,x2,x3,x1x2,x1x3,x2x3,x1x2x3),引數degree = 3,interaction_only = True

注意多項式特徵被隱含地使用在核方法

4 特徵選擇

特徵選擇主要有三種方法:
1. Fliter 過濾法按照發散性或者相關性對各個特徵進行評分,設定閾值或者待選擇閾值的個數,選擇特徵。
2. Wrapper:包裝法,根據目標函式(通常是預測效果評分),每次選擇若干特徵,或者排除若干特徵。
3. Embedded:嵌入法,先使用某些機器學習的演算法和模型進行訓練,得到各個特徵的權值係數,根據係數從大到小選擇特徵。類似於Filter方法,但是是通過訓練來確定特徵的優劣。

4.1 Fliter 過濾法

4.1.1 方差選擇法

使用方差選擇法,先要計算各個特徵的方差,然後根據閾值,選擇方差大於閾值的特徵。使用feature_selection庫的VarianceThreshold類來選擇特徵,是特徵選擇中的一項基本方法。它會移除所有方差不滿足閾值的特徵。預設設定下,它將移除所有方差為0的特徵,即那些在所有樣本中數值完全相同的特徵(類似常數特徵)。

from sklearn.feature_selection import VarianceThreshold

print np.cov(dataset.T)
print dataset[:5,:]
#引數threshold為方差的閾值,該方法會移除方差小於3的特徵,人為選擇閾值具有主觀性
VarianceThreshold(threshold=3).fit_transform(dataset)[:5,:]
[[ 0.68569351 -0.03926846  1.27368233  0.5169038 ]
 [-0.03926846  0.18800403 -0.32171275 -0.11798121]
 [ 1.27368233 -0.32171275  3.11317942  1.29638747]
 [ 0.5169038  -0.11798121  1.29638747  0.58241432]]
[[ 5.1  3.5  1.4  0.2]
 [ 4.9  3.   1.4  0.2]
 [ 4.7  3.2  1.3  0.2]
 [ 4.6  3.1  1.5  0.2]
 [ 5.   3.6  1.4  0.2]]





array([[ 1.4],
       [ 1.4],
       [ 1.3],
       [ 1.5],
       [ 1.4]])

可以看到,特徵方差為對角線上元素,只有一個特徵方差大於3,最後的結果中也至於一列被選出來。

4.1.2 相關係數方法

使用相關係數法,先要計算各個特徵對目標值的相關係數以及相關係數的P值。用feature_selection庫的SelectKBest類結合相關係數來選擇特徵的程式碼如下:

from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr


#選擇K個最好的特徵,返回選擇特徵後的資料
#第一個引數為計算評估特徵是否好的函式,該函式輸入特徵矩陣和目標向量,輸出二元組(評分,P值)的陣列,
#陣列第i項為第i個特徵的評分和P值。在此定義為計算相關係數
#引數k為選擇的特徵個數

print np.array(map(lambda x:pearsonr(x,iris.target),dataset.T))

#print dataset.T

SelectKBest(lambda X,Y:np.array(map(lambda x:pearsonr(x,Y),X.T))[:,0],k=2)\
.fit_transform(dataset,iris.target)[:10,:]
[[  7.82561232e-01   2.89047835e-32]
 [ -4.19446200e-01   9.15998497e-08]
 [  9.49042545e-01   4.15547758e-76]
 [  9.56463824e-01   4.77500237e-81]]





array([[ 1.4,  0.2],
       [ 1.4,  0.2],
       [ 1.3,  0.2],
       [ 1.5,  0.2],
       [ 1.4,  0.2],
       [ 1.7,  0.4],
       [ 1.4,  0.3],
       [ 1.5,  0.2],
       [ 1.4,  0.2],
       [ 1.5,  0.1]])
help(pearsonr)
Help on function pearsonr in module scipy.stats.stats:

pearsonr(x, y)
    Calculates a Pearson correlation coefficient and the p-value for testing
    non-correlation.

    The Pearson correlation coefficient measures the linear relationship
    between two datasets. Strictly speaking, Pearson's correlation requires
    that each dataset be normally distributed, and not necessarily zero-mean.
    Like other correlation coefficients, this one varies between -1 and +1
    with 0 implying no correlation. Correlations of -1 or +1 imply an exact
    linear relationship. Positive correlations imply that as x increases, so
    does y. Negative correlations imply that as x increases, y decreases.

    The p-value roughly indicates the probability of an uncorrelated system
    producing datasets that have a Pearson correlation at least as extreme
    as the one computed from these datasets. The p-values are not entirely
    reliable but are probably reasonable for datasets larger than 500 or so.

    Parameters
    ----------
    x : (N,) array_like
        Input
    y : (N,) array_like
        Input

    Returns
    -------
    r : float
        Pearson's correlation coefficient
    p-value : float
        2-tailed p-value

    References
    ----------
    http://www.statsoft.com/textbook/glosp.html#Pearson%20Correlation

4.1.3 卡方檢驗

經典的卡方檢驗是檢驗定性自變數對定性因變數的相關性。由於它最初是由英國統計學家Karl Pearson在1900年首次提出的,因此也稱之為Pearson χ2,其計算公式為.假設自變數有N種取值,因變數有M種取值,考慮自變數等於i且因變數等於j的樣本頻數的觀察值與期望的差距,構建統計量:
χ2=i=1k(Ainpi)2npi(i=1,2,...,k)

其中,Ai為i水平的觀察頻數,Ei為i水平的期望頻數,n為總頻數,pi為i水平的期望頻率。i水平的期望頻數Ei等於總頻數n×i水平的期望概率pi,k為單元格數。當n比較大時,χ2統計量近似服從k-1(計算Ei時用到的引數個數)個自由度的卡方分佈。
這個統計量的含義簡而言之就是自變數對因變數的相關性。用feature_selection庫的SelectKBest類結合卡方檢驗來選擇特徵的程式碼如下:

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
print dataset[:5,:]
SelectKBest(chi2,k=2).fit_transform(dataset,labels)[:5,:]
[[ 5.1  3.5  1.4  0.2]
 [ 4.9  3.   1.4  0.2]
 [ 4.7  3.2  1.3  0.2]
 [ 4.6  3.1  1.5  0.2]
 [ 5.   3.6  1.4  0.2]]





array([[ 1.4,  0.2],
       [ 1.4,  0.2],
       [ 1.3,  0.2],
       [ 1.5,  0.2],
       [ 1.4,  0.2]])
help(chi2)
Help on function chi2 in module sklearn.feature_selection.univariate_selection:

chi2(X, y)
    Compute chi-squared stats between each non-negative feature and class.

    This score can be used to select the n_features features with the
    highest values for the test chi-squared statistic from X, which must
    contain only non-negative features such as booleans or frequencies
    (e.g., term counts in document classification), relative to the classes.

    Recall that the chi-square test measures dependence between stochastic
    variables, so using this function "weeds out" the features that are the
    most likely to be independent of class and therefore irrelevant for
    classification.

    Read more in the :ref:`User Guide <univariate_feature_selection>`.

    Parameters
    ----------
    X : {array-like, sparse matrix}, shape = (n_samples, n_features_in)
        Sample vectors.

    y : array-like, shape = (n_samples,)
        Target vector (class labels).

    Returns
    -------
    chi2 : array, shape = (n_features,)
        chi2 statistics of each feature.
    pval : array, shape = (n_features,)
        p-values of each feature.

    Notes
    -----
    Complexity of this algorithm is O(n_classes * n_features).

    See also
    --------
    f_classif: ANOVA F-value between label/feature for classification tasks.
    f_regression: F-value between label/feature for regression tasks.

4.1.4 互資訊法

經典的互資訊也是評價定性自變數對定性因變數的相關性的,互資訊計算公式如下:
I(X;Y)=xXyYp(x,y)logp