今天我們要說(shuō)的是,在機(jī)器學(xué)習(xí)常用的算法里面,那些需要?dú)w一化,那些不需要,通過(guò)scikit-learn中的預(yù)處理的一些方法,實(shí)際了解如何正則化和歸一化數(shù)據(jù)。看完本文,應(yīng)該對(duì)于一般的機(jī)器學(xué)習(xí)任務(wù),都可以輕松上手操作。
先看一下歸一化是什么意思,對(duì)于一個(gè)機(jī)器學(xué)習(xí)任務(wù)來(lái)說(shuō),首先要有數(shù)據(jù),數(shù)據(jù)怎么來(lái)?一種情況是別人整理好給你,一種是自己造數(shù)據(jù),根據(jù)不同的業(yè)務(wù)場(chǎng)景,自己提取想要的數(shù)據(jù),一般來(lái)自各個(gè)維度的數(shù)據(jù),也就是常說(shuō)的統(tǒng)計(jì)口徑不一樣,造成的結(jié)果是得到的數(shù)據(jù)大小范圍變換非常大,并且可能數(shù)據(jù)類型也不一樣,統(tǒng)計(jì)學(xué)里面把數(shù)據(jù)分為數(shù)值型數(shù)據(jù)、分類型數(shù)據(jù)、順序型數(shù)據(jù),對(duì)這些數(shù)據(jù)怎么處理成統(tǒng)一的口徑的問(wèn)題,就是機(jī)器學(xué)習(xí)中數(shù)據(jù)歸一化問(wèn)題。
機(jī)器學(xué)習(xí)任務(wù)一般分為3種,也可以是兩種,分類、回歸和聚類,其中聚類也可以看做是分類。如果需要預(yù)測(cè)的值是離散型數(shù)據(jù),就是分類任務(wù),如果預(yù)測(cè)值是連續(xù)型數(shù)據(jù),就是回歸任務(wù)。常用的回歸模型,也幾乎都可以做分類,只需要把輸出變?yōu)榉诸惖念悇e數(shù)的概率值即可。常用的機(jī)器學(xué)習(xí)模型有廣義線性模型,集成模型,線性判別分析、支持向量機(jī)、K近鄰、樸素貝葉斯、決策樹(shù)、感知機(jī)、神經(jīng)網(wǎng)絡(luò)等。其中廣義線性模型包括線性回歸、嶺回歸、Lasso回歸、最小角回歸、邏輯回歸、貝葉斯回歸、多項(xiàng)式回歸、Elastic Net等。集成的方法包括隨機(jī)森林、AdaBoost、梯度樹(shù)提升等。
機(jī)器學(xué)習(xí)中的模型這么多,怎么分的清那個(gè)需要?dú)w一化,那個(gè)不需要呢,這里有一個(gè)一般的準(zhǔn)則,就是需要?dú)w一化的模型,說(shuō)明該模型關(guān)心變量的值,而相對(duì)于概率模型來(lái)說(shuō),關(guān)心的是變量的分布和變量之間的條件概率。所以大部分概率模型不需要?dú)w一化。還有就是如果模型使用梯度下降法求最優(yōu)解時(shí),歸一化往往非常有必要,否則很難收斂甚至不能收斂。
然后說(shuō)一下常用的歸一化的方法,利用scikit-learn這個(gè)工具,把里面提到的歸一化方法挨個(gè)過(guò)一遍。
- 均值,1標(biāo)準(zhǔn)差歸一化,也叫z-score標(biāo)準(zhǔn)化
顧名思義,就是把數(shù)據(jù)的均值變到0,方差變到1,公式為:
其中x是原始數(shù)據(jù),z是變化后的數(shù)據(jù),u是均值,sigma是方差。一般一個(gè)機(jī)器學(xué)習(xí)的數(shù)據(jù)集都是M*N的一個(gè)大的矩陣,M代表樣本數(shù),N代表特征的個(gè)數(shù),其中的均值和方差,指的是整個(gè)大的矩陣的均值和方差,x是任意一個(gè)樣本,xij,即:
下同,不在說(shuō)明。
然后用scikit-learn來(lái)實(shí)現(xiàn)z-score標(biāo)準(zhǔn)化的方法是下面這個(gè):
這里把需要的方法都import進(jìn)來(lái)了,后面不再提示。
import numpy as np
from sklearn import preprocessing
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import FunctionTransformer
diabetes = load_diabetes()
X = diabetes.data
y = diabetes.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
print("X shape:{},y shape:{}".format(X_train.shape, y_train.shape))
X_scaled = preprocessing.scale(X_train, axis=0, with_mean=True, with_std=True, copy=True)
m = X_scaled.mean(axis=0)
s = X_scaled.std(axis=0)
print("Mean:{}, \n Std:{}".format(m, s))
"""
X shape:(331, 10),y shape:(331,)
Mean:[ -4.46101699e-17 2.42840323e-16 2.01248887e-18 -2.12988405e-17
-2.34790368e-17 -2.49884034e-17 -1.25780554e-17 -5.16538809e-17
-1.34165924e-17 1.67707406e-17],
Std:[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
"""
或者
# 另一種方法
scaler = preprocessing.StandardScaler(copy=True, with_mean=True, with_std=True).fit(X_train)
X_scaled = scaler.transform(X_train)
m = X_scaled.mean(axis=0)
s = X_scaled.std(axis=0)
print("Mean:{}, \n Std:{}".format(m, s))
"""
Mean:[ -4.46101699e-17 2.42840323e-16 2.01248887e-18 -2.12988405e-17
-2.34790368e-17 -2.49884034e-17 -1.25780554e-17 -5.16538809e-17
-1.34165924e-17 1.67707406e-17],
Std:[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
"""
- 最大-最小歸一化
就是把數(shù)據(jù)變到[0,1]區(qū)間內(nèi),公式為:
# 最大最小歸一化,歸一化到[0,1]之間
min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)
print()
ma = X_train_minmax.max(axis=0)
mi = X_train_minmax.min(axis=0)
print("max:{},\n min:{}".format(ma, mi))
"""
max:[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.],
min:[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
"""
還有一種是把數(shù)據(jù)歸一到[-1,1]之間,公式為:
# 最大最小歸一化,歸一化到[-1,1]之間
max_abs_scaler = preprocessing.MaxAbsScaler()
x_maxabs = max_abs_scaler.fit_transform(X_train)
ma = x_maxabs.max(axis=0)
mi = x_maxabs.min(axis=0)
print("max:{},\n min:{}".format(ma, mi))
"""
max:[ 1. 1. 1. 1. 1. 1. 1.
1. 1. 0.98435481],
min:[-0.96838121 -0.88085106 -0.52930243 -0.85122699 -0.70749565 -0.58158979
-0.5646737 -0.41242062 -0.94384991 -1. ]
"""
- 正則化
正則化方法包括l1,l2,max正則三種方法,在數(shù)學(xué)里也叫l(wèi)1范數(shù),l2范數(shù),簡(jiǎn)單理解就是取絕對(duì)值和絕對(duì)值的平方在開(kāi)方得到的結(jié)果??创a
X_normalized = preprocessing.normalize(X, norm='l2', axis=1, copy=True, return_norm=False)
# l2, l1, max
print()
print("{},\n {}".format(X[0], X_normalized[0]))
"""
[ 0.03807591 0.05068012 0.06169621 0.02187235 -0.0442235 -0.03482076
-0.04340085 -0.00259226 0.01990842 -0.01764613],
[ 0.32100597 0.42726811 0.52014127 0.18439893 -0.37283438 -0.29356288
-0.36589885 -0.02185454 0.16784162 -0.14876892]
"""
# 另一種方法
normalizer = preprocessing.Normalizer(norm='l2', copy=True).fit(X)
X_normalized = normalizer.transform(X)
print()
print("{},\n {}".format(X[0], X_normalized[0]))
"""
[ 0.03807591 0.05068012 0.06169621 0.02187235 -0.0442235 -0.03482076
-0.04340085 -0.00259226 0.01990842 -0.01764613],
[ 0.32100597 0.42726811 0.52014127 0.18439893 -0.37283438 -0.29356288
-0.36589885 -0.02185454 0.16784162 -0.14876892]
"""
4 變換數(shù)據(jù)的分布
將原始數(shù)據(jù)變換成均勻分布,這樣會(huì)改變?cè)紨?shù)據(jù)的分布和變量間的相關(guān)性。其實(shí)這個(gè)和下面的多項(xiàng)式變換不屬于歸一化處理,只是一種數(shù)據(jù)變換的方式。
quantile_transformer = preprocessing.QuantileTransformer(random_state=0)
X_train_trans = quantile_transformer.fit_transform(X_train)
percentile = np.percentile(a=X_train[:, 0], q=[0, 25, 50, 75, 100], axis=None, out=None,
overwrite_input=False, interpolation='linear', keepdims=False)
print()
print(percentile)
"""
[-0.10722563 -0.0382074 0.00538306 0.03807591 0.11072668]
"""
5.多項(xiàng)式變換
4個(gè)特征的度為2的多項(xiàng)式轉(zhuǎn)換公式為:
然后比如數(shù)據(jù)為(1,4)大小的數(shù)組,[[1,2,3,4]]
# 多項(xiàng)式轉(zhuǎn)換
poly = PolynomialFeatures(degree=2, interaction_only=False, include_bias=True)
X = np.array([[1, 2, 3, 4]])
polyed = poly.fit_transform(X)
print(polyed)
print()
"""
[[ 1. 1. 2. 3. 4. 1. 2. 3. 4. 4. 6. 8. 9. 12.
16.]]
"""
print("{},{}, {}".format(polyed.shape, np.max(polyed), np.min(polyed)))
"""
(1, 15),16.0, 1.0
"""
- 自定義函數(shù)轉(zhuǎn)換
就是你可以用任意你定義的函數(shù),把數(shù)據(jù)變換到另一個(gè)值,看代碼:
# 自定義函數(shù)轉(zhuǎn)換
transformer = FunctionTransformer(func=np.log1p, inverse_func=None, validate=True,
accept_sparse=False, pass_y='deprecated',
kw_args=None, inv_kw_args=None)
transformered = transformer.transform(X)
print()
print("{},\n {}".format(X[0], transformered[0]))
print(np.log1p(0.03807591))
"""
[ 0.03807591 0.05068012 0.06169621 0.02187235 -0.0442235 -0.03482076
-0.04340085 -0.00259226 0.01990842 -0.01764613],
[ 0.03736891 0.04943769 0.05986782 0.02163659 -0.04523118 -0.03544146
-0.04437083 -0.00259563 0.01971284 -0.01780367]
0.0373689130909
"""
下面對(duì)幾個(gè)常用的模型做個(gè)分類,需要說(shuō)明的是,通常歸一化之后,效果會(huì)變好,但是到底歸一不歸一,沒(méi)有一個(gè)確定的說(shuō)法,還是要用結(jié)果說(shuō)話,所以經(jīng)常有人在微信群里問(wèn),某某某個(gè)模型要不要?dú)w一化,其實(shí)你去試試不就知道了,歸一化做一遍,不歸一化做一遍,做個(gè)比較就知道需不需要?dú)w一化了。
需要?dú)w一化的模型有
神經(jīng)網(wǎng)絡(luò),標(biāo)準(zhǔn)差歸一化
支持向量機(jī),標(biāo)準(zhǔn)差歸一化
線性回歸,可以用梯度下降法求解,需要標(biāo)準(zhǔn)差歸一化
PCA
LDA
聚類算法基本都需要
K近鄰,線性歸一化,歸一到[0,1]區(qū)間內(nèi)。
邏輯回歸
不需要?dú)w一化的模型:
決策樹(shù): 每次篩選都只考慮一個(gè)變量,不考慮變量之間的相關(guān)性,所以不需要?dú)w一化。
隨機(jī)森林:不需要?dú)w一化,mtry為變量個(gè)數(shù)的均方根。
樸素貝葉斯
需要正則化的模型:
Lasso
Elastic Net
完!