“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

全文共3819字,預計學習時長18分鐘


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

圖源:unsplash


你一定曾遇到過這樣一個數據集,它具有多個特徵,涵蓋了不同程度的數量級、範圍和單位。這會是一個巨大的阻礙,很少的機器學習算法對這些特徵高度敏感。


其實類似的問題並不少見。例如,一個特徵的單位是千克,另一個的單位是克,還有一個的單位是升。當它們所呈現的內容差異如此之大時,該如何使用這些特徵呢?


該是特徵縮放上場的時候了。這是數據預處理階段的關鍵部分,但很多初學者忽視了這一點,這會損害他們的機器學習模型。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

特性縮放可以顯著提高某些機器學習算法的性能,而對其他算法則完全不起作用。這種怪事背後的原因可能是什麼?


另外,歸一化和標準化的區別是什麼?這是機器學習中最常用的兩種特徵縮放技術,但它們不易理解。什麼時候應該使用哪種技術?


本文將解答你關於特徵縮放的疑問,將在Python中實現特性縮放,讓你對它如何適用於不同的機器學習算法有一個實踐上的理解。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

為什麼要使用特徵縮放?


需要解決的第一個問題是,為什麼需要縮放數據集中的變量。一些機器學習算法對特徵縮放敏感,而另一些則幾乎不變。


基於距離的算法


距離算法(例如KNN、K-means和SVM)受特徵範圍的影響最大。這是因為在後臺,算法使用數據點之間的距離來確定它們的相似性。


例如,假如有一些數據,其中包含高中學生的CGPA分數(從0到5)和他們的未來收入(以千盧比為單位):


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

由於這兩個特徵具有不同的縮放程度,所以有可能給更高量級的特徵更高的權重。這將影響機器學習算法的性能,顯然,我們不希望算法偏向於一個特徵。


因此,我們在使用基於距離的算法之前對數據進行縮放,這樣所有的特徵對結果的影響都是相等的。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

當比較學生A和B的數據點之間的歐氏距離、B和C的數據點之間的歐氏距離,縮放前後的效果是明顯的,如下所示:


· 縮放前AB距離 =>

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

· 縮放前BC距離 =>

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

· 縮放後AB距離 =>

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

· 縮放後BC距離 =>

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

縮放將所有特徵都帶入計算,並且現在的距離比縮放之前更具有可比性。


基於梯度下降的算法


使用梯度下降作為優化技術的機器學習算法(例如線性迴歸、邏輯迴歸、神經網絡等)要求對數據進行縮放。請看下面的梯度下降公式:


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

公式中特徵值X的存在將影響梯度下降的步長。特徵範圍的差異將導致每個特徵的步長不同。為確保梯度下降平穩地向最小值移動,並確保所有特徵的梯度下降步驟均以相同的速率更新,我們在將數據輸入模型之前先對數據進行縮放。


具有相似縮放程度的特徵可以幫助梯度下降更快地收斂到最小值。


基於樹的算法


另一方面,基於樹的算法對特徵縮放非常不敏感。考慮一下,決策樹僅基於單個特徵拆分節點。決策樹在特徵上分割節點,從而增加了節點的同質性。特徵上的拆分不受其他特徵影響。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

圖源:unsplash


因此,其餘特徵對拆分幾乎沒有影響。這就是特徵縮放不改變算法性能的原因!


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

什麼是歸一化?


歸一化是一種縮放技術,對值進行移位和重新縮放,以使它們最終在0到1之間變化。這也稱為“最小-最大”縮放。


這是歸一化的公式:

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

其中,Xmax和Xmin分別為特徵的最大值和最小值。


· 當X的值是列中的最小值時,分子為0,因此X '為0

· 相反,當X的值是列中的最大值時,分子等於分母,因此X '的值是1

· 如果X的值在最小值和最大值之間,那麼X '的值在0和1之間


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

什麼是標準化?


標準化是另一種縮放技術,其中值以具有單位標準偏差的平均值為中心。這意味著特徵的均值變為零,結果分佈具有單位標準差。


這是標準化的公式:

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

μ為特徵值的均值,σ為特徵值的標準差。注意,在這種情況下,值並不侷限於特定的範圍。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

圖源:unsplash


現在,你腦海中最大的問題一定是什麼時候應該使用歸一化,什麼時候應該使用標準化?下面就來看看!

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

最大的問題——歸一化還是標準化?


歸一化與標準化是機器學習初學者的一個永恆的問題。


· 如果數據分佈不遵循高斯分佈,歸一化是很有用的。這在不假設數據分佈的算法(如k近鄰和神經網絡)中很有用。


· 相反,如果數據服從高斯分佈,標準化是有用的。然而,這並不一定對。另外,與歸一化不同,標準化沒有邊界範圍。因此,即使數據中有異常值,也不會受到標準化的影響。


然而,最終使用歸一化還是標準化將取決於問題和正在使用的機器學習算法。沒有硬性的規則來確定何時將數據歸一化或標準化。可以從將模型擬合為原始的、歸一化的和標準化的數據開始,並比較性能以獲得最佳結果。


好的做法是將縮放器與訓練數據進行擬合,然後利用縮放器對測試數據進行轉換。這將避免模型測試過程中的任何數據洩漏。此外,通常不需要調整目標值。

“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

在Python中實現特徵縮放


現在是有趣的部分,將學到的東西付諸實踐。採用DataHack平臺的BigMart數據集,可將特徵縮放應用於一些機器學習算法。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

圖源:unsplash


跳過預處理步驟,因為它們超出了本教程的範圍。但是可以在這篇文章中找到預處理的詳細解釋。這些步驟將使你能夠在黑客馬拉松排行榜上排名前20位,因此值得一試!


因此,首先將數據分為訓練和測試集:


<code>       # spliting training and testing data
from sklearn.model_selection import train_test_split
X= df
y= target
X_train, X_test, y_train, y_test =train_test_split(X,y,test_size=0.2,random_state=27)/<code>


在轉到特徵縮放部分之前,使用pd.describe()方法瀏覽有關數據的詳細信息:


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

可以看到,特徵的值範圍存在巨大差異:Item_Visibility,Item_Weight,Item_MRP和Outlet_ Establishmentment_Year。嘗試使用特徵縮放來解決該問題!


注意:特徵Item_Visibility中有負值,這是因為已採用對數轉換來處理特徵中的偏斜度。


使用sklearn進行歸一化


為了歸一化數據,需要從sklearn庫導入MinMaxScalar並將其應用於數據集。所以,下面就開始吧!


<code>         # data normalization with sklearn
from sklearn.preprocessing importMinMaxScaler
# fitscaler on training data
norm=MinMaxScaler().fit(X_train)
#transform training data
X_train_norm= norm.transform(X_train)
#transform testing dataabs
X_test_norm= norm.transform(X_test)/<code>


請看歸一化如何影響數據集:


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

現在,所有特徵的最小值均為0,最大值為1。完美!


接下來,嘗試對數據進行標準化。


使用sklearn進行標準化


為了對數據進行標準化,需要從sklearn庫中導入StandardScalar並將其應用於數據集。方法如下:


<code>         # data standardization with sklearn
from sklearn.preprocessing importStandardScaler
#numerical features
num_cols= ['Item_Weight','Item_Visibility','Item_MRP','Outlet_Establishment_Year']
# applystandardization on numerical features
for i in num_cols:
# fit on trainingdata
scale =StandardScaler().fit(X_train[[i]])
# transform thetraining data
X_train_stand[i] = scale.transform(X_train_stand[[i]])
# transform thetesting data
X_test_stand[i] = scale.transform(X_test_stand[[i]])/<code>


可以發現,只對數字列應用了標準化,而沒有對其他的單一熱編碼(One-HotEncoded)特徵應用標準化。標準化單一熱編碼特徵意味著將類別特徵重新分佈。你不會想這麼做的!


但是為什麼在對數據進行歸一化時沒有做同樣的事情呢?因為單一熱編碼的特徵已經在0到1之間了。所以,標準化不會影響它們的值。


好的,來看看標準化是如何改變數據的:


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

現在,特徵的值以平均值為中心,具有單位標準偏差分佈。太棒了!


比較未縮放、歸一化和標準化的數據


可視化數據以瞭解當前分佈總是很不錯的。可以使用箱線圖來比較未縮放數據和已縮放數據。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

你會注意到,特徵縮放考慮到了方方面面。這些特徵現在更具可比性,並且會對學習模型產生類似的影響。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

將縮放應用於機器學習算法


是時候在數據上訓練一些機器學習算法,以比較不同縮放技術對算法性能的影響。特別注意縮放對三種算法的影響:K-近鄰、支持向量迴歸和決策樹。


K-近鄰(KNN)


如前所述,KNN是一種基於距離的算法,受特徵範圍的影響。來看看縮放前後數據對性能的影響:


<code>         # training a KNN model
from sklearn.neighbors importKNeighborsRegressor
# measuring RMSE score
from sklearn.metrics import mean_squared_error
# knn
knn=KNeighborsRegressor(n_neighbors=7)
rmse= []
# raw,normalized and standardized training and testing data
trainX= [X_train, X_train_norm, X_train_stand]
testX= [X_test, X_test_norm, X_test_stand]
# modelfitting and measuring RMSE
for i inrange(len(trainX)):
# fit
knn.fit(trainX[i],y_train)
# predict
pred = knn.predict(testX[i])
# RMSE
rmse.append(np.sqrt(mean_squared_error(y_test,pred)))
#visualizing the result
df_knn= pd.DataFrame({'RMSE':rmse},index=['Original','Normalized','Standardized'])
df_knn/<code>


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

可以看到,特徵縮放降低了KNN模型的RMSE分數。具體來說,歸一化數據的性能比標準化數據稍好一些。


注意:之所以測量RMSE,因為這個比賽中評估RMSE。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

圖源:unsplash


支持向量迴歸(SVR)


SVR是另一種基於距離的算法。所以,來看看它是在歸一還是或標準化的情況下工作得更好:


<code>         # training an SVR model
from sklearn.svm importSVR
# measuring RMSE score
from sklearn.metrics import mean_squared_error
# SVR
svr=SVR(kernel='rbf',C=5)
rmse= []
# raw,normalized and standardized training and testing data
trainX= [X_train, X_train_norm, X_train_stand]
testX= [X_test, X_test_norm, X_test_stand]
# modelfitting and measuring RMSE
for i inrange(len(trainX)):
# fit
svr.fit(trainX[i],y_train)
# predict
pred = svr.predict(testX[i])
# RMSE
rmse.append(np.sqrt(mean_squared_error(y_test,pred)))
#visualizing the result
df_svr= pd.DataFrame({'RMSE':rmse},index=['Original','Normalized','Standardized'])
df_svr/<code>


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

可以看到特徵縮放確實降低了RMSE的分數。標準化數據的表現優於歸一化數據。為什麼會這樣呢?


sklearn文檔表明,SVR使用RBF核,假設所有特徵都以0為中心,方差相同。這是因為一個方差大於其他方差的特徵會阻止評估器從這些特徵中學習。


決策樹


已知特徵縮放對於決策樹沒有影響。此處展示一個實例,展示決策樹是如何操作數據的:


<code># training a Decision Tree model
from sklearn.tree importDecisionTreeRegressor
# measuring RMSE score
from sklearn.metrics import mean_squared_error
#Decision tree
dt=DecisionTreeRegressor(max_depth=10,random_state=27)
rmse= []
# raw,normalized and standardized training and testing data
trainX= [X_train,X_train_norm,X_train_stand]
testX= [X_test,X_test_norm,X_test_stand]
# modelfitting and measuring RMSE
for i inrange(len(trainX)):

# fit
dt.fit(trainX[i],y_train)
# predict
pred = dt.predict(testX[i])
# RMSE
rmse.append(np.sqrt(mean_squared_error(y_test,pred)))
#visualizing the result
df_dt= pd.DataFrame({'RMSE':rmse},index=['Original','Normalized','Standardized'])
df_dt/<code>


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

可以看到,RMSE分數在特徵縮放時並一點也沒變。因此,可以放心在數據上使用基於樹的算法!


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

圖源:unsplash


要記住的是,何時使用歸一化還是標準化永遠沒有標準答案。這完全取決於數據和使用的算法。接下來輪到你了,試試用其他算法進行特徵縮放吧。


“千克”“毫升”單位不同怎麼辦?該是特徵縮放上場的時候了

我們一起分享AI學習與發展的乾貨


分享到:


相關文章: