今天這篇還是講特徵工程那一堆事,準確點說是數據預處理範疇內的,在做PCA降維時,我發現利用方差過濾出的主成分和利用PCA降維得到的主成分對應位置的方差有些不同:

VarianceThreshold:[90370.21684180899, 55277.04960170764, 51395.858083599174]
PCA:[176251.93379431,74196.48270488,55716.27982124]

之前說過PCA降維可以將原來高維的數據投影到某個低維的空間上並使得其方差儘量大。如果數據其中某一特徵的數值特別大的話,那麼它在整個誤差計算的比重上就很大。所以將數據投影到低維空間之後,整個投影會去努力逼近數值最大的那一個特徵,而忽略數值比較小的特徵。

在建模前我們不知道每個特徵的重要性,這很可能導致了大量的信息缺失。爲了“公平”起見,防止過分捕捉某些數值大的特徵,我們就可以先對每個特徵先進行標準化處理,使得它們的大小都在相同的範圍內,然後再進行PCA。

我們要處理的數據往往有着不同的量綱和量綱單位,這樣的情況會影響到數據分析的結果,爲了消除特徵之間的量綱影響,需要進行數據標準化處理。原始數據經過數據標準化處理後,數據集中每個特徵就處於同一數量級,適合進行綜合對比評價。

上面文字敘述可能相對抽象,就先通過一個簡單的例子深入瞭解一下標準化和歸一化的重要性。假如一個人的健康狀況可以根據一個公式計算:

$$健康狀況=3\times身高+2\times體重$$

現在我們有一份數據集,有身高和體重兩個特徵,身高的單位爲米,體重的單位爲斤:

身高(米) 體重(斤) 健康狀況
1.7 120 245.1
1.6 200 404.8
2.0 140 286

即使在公式中身高所佔權重要大於體重,但是由於這兩個特徵數值之間出現了兩極化,所以最後一個人的健康狀況很大程度向體重傾斜,所以若想正確的評判一個人的健康狀況,那麼需要中和一下兩類數值,可以將其映射至[0,1]區間內,也就是進行歸一化處理:

身高(米) 體重(斤) 健康狀況
0.25 0 0.5
0 1 2
1 0.25 3.5

處理之後再預測時,就不會出現向某個特徵傾斜的狀況,兩個特徵的重要性就取決於公式中係數的大小。

歸一化

歸一化就是將訓練集中某一列數值特徵的值縮放到0和1之間,公式如下:

$$X_{norm}=\frac{X-X_{min}}{X_{max}-X_{min}}$$

其中$X_{max}$爲樣本最大值,$X_{min}$爲樣本最小值。可以看到每個樣本的歸一化都是要依據數據中最大值和最小值進行的,所以歸一化對數據集中的異常點是比較敏感的。因爲異常點通常是離羣點,那麼它的值可能就過大或者過小,如果歸一化依據異常點進行的話,最後的結果就會產生很大的偏差。所以在歸一化很適合精確且規模相對小一些的數據集,一般在歸一化之前可以先檢查數據,排除異常點的影響。

利用numpy實現歸一化的代碼如下:

def normalization(data):
    M_m = np.max(data)-np.min(data)
    return (data-np.min(data)) / M_m

標準化

標準化就是將訓練集中某一列數值特徵的值縮放成均值爲0,方差爲1的狀態。公式如下:

$$X_{std} = \frac{X-\mu}{\sigma}$$

其中$\mu$爲樣本均值、$\sigma$爲樣本標準差,$\sigma$也考量了數據穩定性。每一個樣本的歸一化僅和最大值、最小值和它本身有關,這點和標準化是有一些出入的,標準化的縮放處理和每一個樣本點都有關係,因爲均值和標準差是數據集整體的,與歸一化相比,標準化更加註重數據集中樣本的分佈狀況。由於具有一定的樣本個數,所以出現少量的異常點對於平均值和標準差的影響較小,因此標準化的結果也不會具有很大的偏差。

利用numpy實現標準的代碼如下:

def standardization(data):
    mu = np.mean(data, axis=0)
    sigma = np.std(data, axis=0)
    return (data - mu) / sigma

綜上很容易推斷出歸一化和標準化本質上都是對原始數據進行縮放和平移,只是着重點不同。

在sklearn庫中也有歸一化和標準化對應的API,應用起來也很簡單,歸一化應用方法:

from sklearn.preprocessing import MinMaxScaler
import numpy as np
X = [[83,2,10],
     [60,3,15],
     [75,4,13]]
X = np.array(X)
Mm = MinMaxScaler()
data = Mm.fit_transform(X)
print(data)

歸一化輸出對應結果:

[[1.         0.         0.        ]
 [0.         0.5        1.        ]
 [0.65217391 1.         0.6       ]]

標準化應用方法:

from sklearn.preprocessing import StandardScaler
import numpy as np

X = [[83,2,10],
     [60,3,15],
     [75,4,13]]
X = np.array(X)
Mm = StandardScaler()
data = Mm.fit_transform(X)
print(data)

標準化輸出對應結果:

[[ 1.08388958 -1.22474487 -1.29777137]
 [-1.32863884  0.          1.13554995]
 [ 0.24474926  1.22474487  0.16222142]]

那麼是所有的機器學習算法建模之前都需要對相應的數據進行標準化和歸一化處理嗎?肯定不是的。其中KNN算法、支持向量機、線性迴歸、神經網絡是需要進行標準化或歸一化處理的,不難發現這幾種算法都與"距離"相關,所以在進行計算時爲了避免預測結果向數值大的特徵傾斜,所以標準化處理是必要的,可以很大程度提高模型的精度。

而邏輯迴歸是否要標準化則取決於是否應用正則化,標準化可以很好的提高收斂速度,這很好的體現在梯度下降法和梯度上升法中,如下圖:

左圖爲標準化之前,右圖爲標準化之後,可以看到標準化可以讓模型少走很多彎路,從而加快收斂速度,這一點也很容易想象,畢竟個位數與千位數、個位數與個位數之間的"距離"差距還是很大的。

決策樹和樸素貝葉斯算法是不需要進行標準化的,因爲前者是通過信息增益進行決策,後者是通過概率進行評判,這類模型不關心變量的取值,而是關心變量的分佈和變量之間的條件概率,與"距離"計算無關,繼而以決策樹爲基礎構建的隨機森林、AdaBoost等等也不需要標準化,但是需要注意的是,在應用這些算法之前若要使用PCA降維則需要進行標準化。

那麼歸一化和標準化如何選擇呢?這個沒有準確的答案,如果時間允許,可以嘗試兩種處理方法擇最優。如果時間不允許,可以根據數據和要求選擇:

  • 如果數據集小而穩定,可以選擇歸一化
  • 如果數據集中含有噪聲和異常值,可以選擇標準化,標準化更加適合嘈雜的大數據集。

關注公衆號【奶糖貓】第一時間獲取更多精彩好文

相關文章