機器學習~KNN算法的更多思考

KNN算法引出的問題

迴歸我們最開始的KNN算法例子,具備兩個特徵,時間和腫瘤大小,兩個特徵基本在一個尺度上,但是在現實生活中,特徵與特徵之間,很少有在一個尺度上的,就比如上面的時間並非一定要在1-10之間,可以是分鐘級別,甚至秒級別;獲取到的特徵可能不一定都是數字,比如有性別男女等;獲得的原始數據並非一定都是齊全的等等。

我們首先對上面描述的問題來一一解答

數據歸一化

如上文所說:特徵與特徵之間,很少有在同一尺度的,就拿我們的腫瘤案例來講:兩個腫瘤的大小可能是1cm和5cm,發現時間爲100天和200天,如果我們不對數據做處理,直接進行knn分類,那麼就會發現在求距離的時候,結果就會被時間所主導,導致分類結果不準確。
所以一般來說,我們都需要將數據映射到同一尺度上,即數據歸一化。

最值歸一化(normalization)

最值歸一化是指將所有數據都映射到0-1之間
xscale=xxminxmaxxmin x_{scale} = \frac{x-x_{min}}{x_{max}-x_{min}}
最值歸一化適用於分佈有明顯邊界的情況:比如像素的分佈,肯定是在0-255之間,分數0-100分等等。
對於沒有明顯邊界的數據,受最值歸一化的邊界影響會比較大,分類會造成不準確。

均值方差歸一化(standardization)

均值方差歸一化是把所有數據歸一到均值爲0方差爲1的分佈中,即讓數據服從標準正態分佈。
xscale=xxmeans x_{scale} = \frac{x-x_{mean}}{s}
均值方差歸一化適用於分佈沒有明顯邊界的情況,比如一些連續的數據,有可能是會存在極端數據值。均值方差歸一化後雖然不能保證數據肯定是落在一定範圍內,但是根據正態分佈的特性,我們可以知道,數據肯定是出現在一個尺度之內。
在這裏對我們之前KNN中的示例數據進行兩種歸一化

sklearn實現

from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
import numpy as np

raw_data_X = [[3.393533211, 2.331273381],
              [3.110073483, 1.781539638],
              [1.343808831, 3.368360954],
              [3.582294042, 4.679179110],
              [2.280362439, 2.866990263],
              [7.423436942, 4.696522875],
              [5.745051997, 3.533989803],
              [9.172168622, 2.511101045],
              [7.792783481, 3.424088941],
              [7.939820817, 0.791637231]]
#初始化最值歸一化
minMaxscaler = MinMaxScaler() 
X_train = np.array(raw_data_X)
#歸一化的過程跟訓練模型一樣
minMaxscaler.fit(X_train) 
#輸出歸一化的數據
X_train_standard = minMaxscaler.transform(X_train)
"""
OUT:
array([[0.26183319, 0.39428457],
       [0.22562385, 0.25350356],
       [0.        , 0.65987175],
       [0.28594562, 0.99555844],
       [0.11963599, 0.53147601],
       [0.77661583, 1.        ],
       [0.56221779, 0.70228755],
       [1.        , 0.44033653],
       [0.8237964 , 0.6741431 ],
       [0.84257905, 0.        ]])  
"""
#繪製圖
import matplotlib.pyplot as plt
plt.scatter(X_train[:,0],X_train[:,1],color='b')
plt.scatter(X_train_standard[:,0],X_train_standard[:,1],color='g')
plt.show()             

如下所示,綠色是歸一化後的值,可以看到是在0-1之間,藍色是原始值。
在這裏插入圖片描述

#使用均值方差歸一化
standardScaler = StandardScaler() 
standardScaler.fit(X_train)
X_train_standard_v2 = standardScaler.transform(X_train)
plt.scatter(X_train_standard_v2[:,0],X_train_standard_v2[:,1],color='r')
plt.show()

可以看到均值方差歸一化後,是將數據分佈於標準正態分佈中,沒有明顯的邊界
在這裏插入圖片描述

缺失數據處理

除了數據歸一化,我們在現實生活中獲得的訓練集有時候並非一定是完整的,有時候有的特徵字段比較重要的字段缺失很嚴重,又不能捨棄該特徵。因此我們有時候需要對這些缺失的特徵進行處理。
這裏只是簡單說明一下填補的策略有多種:可以用均值,中位數,衆數,或者默認指定值來進行填補,後面到具體應用時,再來看如何填補

分類特徵處理

在機器學習中,大多數算法只能處理都只能處理數值型的數據,不能處理文字,但是我們在生活中很多的標籤和特徵都是文字,比如學歷可能是[“小學”,“初中”,“高中”,“大學”],出行方式可能是[“火車”,“汽車”,“飛機”]等等,所以爲了讓數據適應算法和庫,我們需要對數據進行編碼,將文字型數據轉化爲數值型。

再對特徵進行編碼的時候,考慮三種不同的分類數據:
1>艙門(S,C,Q)
三種取值是完全獨立的,互不影響的,我們稱其爲名義變量
2>學歷(小學,初中,高中)
學歷有高低,初中大於小學,但是學歷取值之間卻不是可以計算的,稱爲有序變量
3>體重(>45kg,>90kg,>135kg)
各個取值之間有聯繫,且是可以互相計算的,比如120kg - 45kg = 90kg,分類之間可以通過數學計算互相轉換。稱爲有距變量

但是我們在進行特徵編碼的時候,這三類編碼都會被我們轉爲[0,1,2],而這三個數字在算法看來,是連續且可以計算的。所以算法會把艙門,學歷這樣的分類特徵,都誤會成是體重這樣的分類特徵。這是由於我們在把分類轉換成數字的時候,忽略了數字中自帶的數學性質,所以給算法傳達了一些不準確的信息,造成了我們模型的不準確。
所以一般對於名義變量,我們使用啞變量的方式來處理,才能保證給算法傳達的信息是準確的。
例如:
在這裏插入圖片描述
這樣的描述,纔會讓算法理解爲,三個是互相獨立的,沒有任何的關係。

參考

sklearn中的數據預處理和特徵工程
機器學習的敲門磚:歸一化與KD樹

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章