數據預處理
數據預處理的過程: 輸入數據 -> 模型 -> 輸出數據
如下圖所示為數據樣本矩陣,則一行一樣本,一列一特征。機器學習中有一個數據預處理的庫,是一個解決機器學習問題的科學計算工具包 sklearn.preprocessing。
年齡 | 學歷 | 經驗 | 性別 | 月薪 |
---|---|---|---|---|
25 | 碩士 | 2 | 女 | 10000 |
20 | 本科 | 3 | 男 | 8000 |
... | ... | ... | ... | ... |
均值移除(標准化)
由於一個樣本的不同特征值差異較大,不利於使用現有機器學習算法進行樣本處理。均值移除可以讓樣本矩陣中的每一列的平均值為0,標准差為1。
例如有一列特征值表示年齡: 17, 20, 23,在不使用庫的情況下,如何使樣本矩陣中的每一列的平均值為0呢?
mean = (17 + 20 + 23)/3 = 20 a' = 17 - 20 = -3 b' = 20 - 20 = 0 c' = 23 - 20 = 3
如何使樣本矩陣中的每一列的標准差為1呢?
s = std(a', b', c') [a'/s, b'/s, c'/s]
我們可以使用sklearn.processing.scale均值移除函數一步實現,均值移除API:
raw_samples = np.array([ [17., 100., 4000], [20., 80., 5000], [23., 75., 5500]]) std_samples = sp.scale(raw_samples) # [[-1.22474487 1.38873015 -1.33630621] # [ 0. -0.46291005 0.26726124] # [ 1.22474487 -0.9258201 1.06904497]] print(std_samples.mean(axis=0)) # [ 0.00000000e+00 -3.70074342e-17 5.18104078e-16] print(std_samples.std(axis=0)) # [ 0.00000000e+00 -3.70074342e-17 5.18104078e-16]
范圍縮放
將樣本矩陣中的每一列的最小值和最大值設定為相同的區間,統一各列特征值的范圍。一般情況下會把特征值縮放至[0, 1]區間。
例如有一列特征值表示年齡: [17, 20, 23],每個元素減去特征值數組所有元素的最小值,即可使一組特征值的最小值為0
$$[17-17, 20-17, 23-17]-->[0, 3, 6]$$
把特征值數組的每個元素除以最大值即可使一組特征值的最大值為1
$$[\frac{0}{6}, \frac{3}{6}, \frac{6}{6}]-->[0, \frac{1}{2}, 1]$$
sklearn.preprocessing.MinMaxScaler范圍縮放API:
# 創建MinMax縮放器 mms = sp.MinMaxScaler(feature_range=(0, 1)) # 調用mms對象的方法執行縮放操作, 返回縮放過后的結果 result = mms.fit_transform(原始樣本矩陣)
案例:
import numpy as np import sklearn.preprocessing as sp raw_samples = np.array([[17., 100., 4000], [20., 80., 5000], [23., 75., 5500]]) # 根據給定范圍創建一個范圍縮放器 mms = sp.MinMaxScaler(feature_range=(0, 1)) # 用范圍縮放器實現特征值的范圍縮放 mms_samples = mms.fit_transform(raw_samples) # [[0. 1. 0. ] # [0.5 0.2 0.66666667] # [1. 0. 1. ]]
歸一化
把需要處理的數據經過處理后(通過某種算法)限制在一定范圍內。首先歸一化是為了后面數據處理的方便,其次是保正程序運行時收斂加快。同時有些情況每個樣本的每個特征值 具體的值並不重要,但是每個樣本特征值的占比更加重要。歸一化一般來說有兩種做法:
第一種做法將輸入轉化到范圍 [0, 1] 之間:
$$y=\frac{x-x_{min}}{x_{max}-x_{min}}$$
公式中$x_{max}$表示輸入值的最大值,$x_{min}$表示輸入值的最小值,這種方法還是會保持輸入大於等於0。這種歸一化一般用於圖像處理。
第一種做法將輸入轉化到范圍 [-1, 1] 之間:
$$y=\frac{x-x_{avg}}{x_{max}-x_{min}}$$
公式中$x_{avg}$表示輸入值的平均值,那么經過這種歸一化之后,輸入會產生負值。這種歸一化一般用於音頻處理。
我們先來講解第一種歸一化方法
python | Java | PHP | |
2017 | 10 | 20 | 5 |
2018 | 8 | 5 | 0 |
變換后的樣本矩陣,每個樣本的特征值絕對值之和為1。
sklearn.preprocessing.normalize(array, norm='l1')
參數:
- array 原始樣本矩陣
- norm 范數:
- l1:l1范數,向量中個元素絕對值之和;
- l2:l2范數,向量中個元素平方之和
返回歸一化預處理后的樣本矩陣
import numpy as np import sklearn.preprocessing as sp raw_samples = np.array([[17., 100., 4000], [20., 80., 5000], [23., 75., 5500]]) # 歸一化預處理 nor_samples = sp.normalize(raw_samples, norm='l1') # [[0.00412922 0.02428953 0.97158125] # [0.00392157 0.01568627 0.98039216] # [0.00410861 0.01339764 0.98249375]] print(abs(nor_samples).sum(axis=1)) # [1. 1. 1.]
標准化
對原始數據進行縮放處理,限制在一定的范圍內。一般指正態化,即均值為0,方差為1。即使數據不符合正態分布,也可以采用這種方式方法,標准化后的數據有正有負。
二值化
有些業務並不需要分析矩陣的詳細完整數據(比如圖像邊緣識別只需要分析出圖像邊緣即可),可以根據一個事先給定的閾值,用0和1表示特征值不高於或高於閾值。二值化后的數組中每個元素非0即1,達到簡化數學模型,較少后面數據計算量的目的。
bin = sklearn.preprocessing.Binarizer(threshold=閾值) 給出閾值, 獲取二值化器
- 調用transform方法對原始樣本矩陣進行二值化預處理操作
result = bin.transform(原始樣本矩陣)
import numpy as np import sklearn.preprocessing as sp raw_samples = np.array([[17., 100., 4000], [20., 80., 5000], [23., 75., 5500]]) bin = sp.Binarizer(threshold=80) # 根據給定的閾值創建一個二值化器 bin_samples = bin.transform(raw_samples) # 通過二值化器進行二值化預處理 # [[0. 1. 1.] # [0. 0. 1.] # [0. 0. 1.]]
獨熱編碼
獨熱編碼獨熱編碼(one-hot encoding)為樣本特征的每個值建立一個由一個1和若干個0組成的序列,用該序列對所有的特征值進行編碼。
也可以理解為將一個值轉化為概率分布的向量,一般用於分類問題。
samples = np.array([[1., 3., 2], [7., 5., 4], [1., 8., 6], [7., 8., 9.]])
兩種數 | 三種數 | 四種數 |
1 | 3 | 2 |
7 | 5 | 4 |
1 | 8 | 6 |
7 | 3 | 9 |
為每一個數字進行獨熱編碼:
1-10 3-100 2-1000
7-01 5-010 4-0100
8-001 6-0010
9-0001
編碼完畢后得到最終經過獨熱編碼后的樣本矩陣
101001000
010100100
100010010
011000001
ohe = sklearn.preprocessing.OneHotEncoder(sparse=是否采用緊縮格式, dtype=數據類型) 創建一個獨熱編碼器
參數:
- sparse: 是否使用緊縮格式(稀疏矩陣)
- dtyle: 數據類型
方法:
- result = ohe.fit_transform(原始樣本矩陣) 對原始樣本矩陣進行處理,返回獨熱編碼后的樣本矩陣。
- encode_dict = ohe.fit(原始樣本矩陣) 對原始樣本矩陣進行訓練,得到編碼字典
- result = encode_dict.transform(原始樣本矩陣) 調用encode_dict字典的transform方法 對數據樣本矩陣進行獨熱編碼
import numpy as np import sklearn.preprocessing as sp raw_samples = np.array([[17., 100., 4000], [20., 80., 5000], [23., 75., 5500]]) ohe = sp.OneHotEncoder(sparse=False, dtype=int) # 創建獨熱編碼器 # 方法1 ohe_dict = ohe.fit(raw_samples) result1 = ohe_dict.transform(raw_samples) print(result1) # 方法2 result2 = ohe.fit_transform(raw_samples) print(result2) # [[1 0 0 0 0 1 1 0 0] # [0 1 0 0 1 0 0 1 0] # [0 0 1 1 0 0 0 0 1]]
標簽編碼
根據字符串形式的特征值在特征序列中的位置,為其指定一個數字標簽,用於提供給基於數值算法的學習模型。
lbe = sklearn.preprocessing.LabelEncoder() 獲取標簽編碼器
方法:
- result = lbe.fit_transform(原始樣本矩陣) 訓練並且為原始樣本矩陣進行標簽編碼
- samples = lbe.inverse_transform(result) 根據標簽編碼的結果矩陣反查字典 得到原始數據矩陣
import numpy as np import sklearn.preprocessing as sp raw_samples = np.array(['audi', 'ford', 'audi', 'toyota', 'ford', 'bmw', 'toyota', 'ford', 'audi']) lbe = sp.LabelEncoder() lbe_samples = lbe.fit_transform(raw_samples) # [0 2 0 3 2 1 3 2 0] inv_samples = lbe.inverse_transform(lbe_samples) # ['audi' 'ford' 'audi' 'toyota' 'ford' 'bmw' 'toyota' 'ford' 'audi']