更新時(shí)間:2019年09月18日17時(shí)20分 來源:傳智播客 瀏覽次數(shù):
在SparkMllib中主要分為特征抽取、特征轉(zhuǎn)化、特征選擇,特別是在特征轉(zhuǎn)化方面是從一個(gè)DataFrame轉(zhuǎn)化為另外一個(gè)DataFrame,在數(shù)值型數(shù)據(jù)處理的時(shí)候我們對(duì)機(jī)器學(xué)習(xí)數(shù)據(jù)集中的樣本和特征部分進(jìn)行單獨(dú)的處理,這里就涉及對(duì)樣本的正則化操作和數(shù)值型特征的歸一化和標(biāo)準(zhǔn)化的方法,今天就帶大家理解這一部分的思考和認(rèn)識(shí)。
1.數(shù)據(jù)歸一化
什么是數(shù)據(jù)的歸一化?
答:數(shù)據(jù)的標(biāo)準(zhǔn)化是將數(shù)據(jù)按比例縮放,使之落入一個(gè)小的特定區(qū)間。在某些比較和評(píng)價(jià)的指標(biāo)處理中經(jīng)常會(huì)用到,去除數(shù)據(jù)的單位限制,將其轉(zhuǎn)化為無量綱的純數(shù)值,便于不同單位或量級(jí)的指標(biāo)能夠進(jìn)行比較和加權(quán)。其中最典型的就是數(shù)據(jù)的歸一化處理,即將數(shù)據(jù)統(tǒng)一映射到[0,1]區(qū)間上。
為什么對(duì)數(shù)據(jù)歸一化處理?
我們?cè)趯?duì)數(shù)據(jù)進(jìn)行分析的時(shí)候,往往會(huì)遇到單個(gè)數(shù)據(jù)的各個(gè)維度量綱不同的情況,比如對(duì)房子進(jìn)行價(jià)格預(yù)測(cè)的線性回歸問題中,我們假設(shè)房子面積(平方米)、年代(年)和幾居室(個(gè))三個(gè)因素影響房?jī)r(jià),其中一個(gè)房子的信息如下:
面積(S):150 平方米
年代(Y):5 年
這樣各個(gè)因素就會(huì)因?yàn)榱烤V的問題對(duì)模型有著大小不同的影響,但是這種大小不同的影響并非反應(yīng)問題的本質(zhì)。
為了解決這個(gè)問題,我們將所有的數(shù)據(jù)都用歸一化處理至同一區(qū)間內(nèi)。
2.數(shù)據(jù)標(biāo)準(zhǔn)化
什么是標(biāo)準(zhǔn)化(StandardScaler)?
訓(xùn)練集中某一列數(shù)值特征(假設(shè)是第i列)的值縮放成均值為0,方差為1的狀態(tài)。標(biāo)準(zhǔn)化之后,數(shù)據(jù)的范圍并不一定是0-1之間,數(shù)據(jù)不一定是標(biāo)準(zhǔn)正態(tài)分布,因?yàn)闃?biāo)準(zhǔn)化之后數(shù)據(jù)的分布并不會(huì)改變,如果數(shù)據(jù)本身是正態(tài)分布,那進(jìn)行標(biāo)準(zhǔn)化之后就是標(biāo)準(zhǔn)正態(tài)分布。
(1)歸一化和標(biāo)準(zhǔn)化的相同點(diǎn)都是對(duì)某個(gè)特征(column)進(jìn)行縮放(scaling)而不是對(duì)某個(gè)樣本的特征向量(row樣本數(shù)據(jù))進(jìn)行縮放。對(duì)行進(jìn)行縮放是毫無意義的。比如三列特征:身高、體重、血壓。每一條樣本(row)就是三個(gè)這樣的值,對(duì)這個(gè)row無論是進(jìn)行標(biāo)準(zhǔn)化還是歸一化都是無意義的,因?yàn)槟悴荒軐⑸砀摺Ⅲw重和血壓混到一起去。
(2)標(biāo)準(zhǔn)化/歸一化的好處
提升模型精度:基于距離的算法,例如Kmeans、KNN等,各個(gè)特征的量綱直接決定了模型的預(yù)測(cè)結(jié)果。舉一個(gè)簡(jiǎn)單的例子,在KNN中,我們需要計(jì)算待分類點(diǎn)與所有實(shí)例點(diǎn)的距離。假設(shè)每個(gè)實(shí)例點(diǎn)(instance)由n個(gè)features構(gòu)成。如果我們選用的距離度量為歐式距離,如果數(shù)據(jù)預(yù)先沒有經(jīng)過歸一化,那么那些絕對(duì)值大的features在歐式距離計(jì)算的時(shí)候起了決定性作用。對(duì)于PCA,如果沒有對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化,部分特征的所占的信息可能會(huì)虛高。
提升收斂速度:例如,對(duì)于linear model來說,數(shù)據(jù)歸一化后,最優(yōu)解的尋優(yōu)過程明顯會(huì)變得平緩,更容易正確的收斂到最優(yōu)解。對(duì)于SVM標(biāo)準(zhǔn)化之后梯度下降的速度加快。
3.標(biāo)準(zhǔn)化和歸一化的對(duì)比分析
(1)標(biāo)準(zhǔn)化/歸一化的對(duì)比分析
首先明確,在機(jī)器學(xué)習(xí)中,標(biāo)準(zhǔn)化是更常用的手段。
MinMaxScaler對(duì)異常值非常敏感。例如,比如三個(gè)樣本,某個(gè)特征的值為1,2,10000,假設(shè)10000這個(gè)值是異常值,用歸一化的方法后,正常的1,2就會(huì)被“擠”到一起去。在PCA,聚類,邏輯回歸,支持向量機(jī),神經(jīng)網(wǎng)絡(luò)這些算法中,StandardScaler往往是最好的選擇。
當(dāng)數(shù)據(jù)需要被壓縮至一個(gè)固定的區(qū)間時(shí),我們使用MinMaxScaler.
(2)在邏輯回歸中需要使用標(biāo)準(zhǔn)化么?
如果你不用正則,那么,標(biāo)準(zhǔn)化并不是必須的,如果你用正則,那么標(biāo)準(zhǔn)化是必須的。為什么呢?因?yàn)椴挥谜齽t時(shí),我們的損失函數(shù)只是僅僅在度量預(yù)測(cè)與真實(shí)的差距,加上正則后,我們的損失函數(shù)除了要度量上面的差距外,還要度量參數(shù)值是否足夠小。而參數(shù)值的大小程度或者說大小的級(jí)別是與特征的數(shù)值范圍相關(guān)的。
舉一例來說,我們預(yù)測(cè)身高,體重用kg衡量時(shí),訓(xùn)練出的模型是: 身高 = x*體重+y*父母身高,X是我們訓(xùn)練出來的參數(shù)。當(dāng)我們的體重用噸來衡量時(shí),x的值就會(huì)擴(kuò)大為原來的1000倍。在上面兩種情況下,都用L1正則的話,顯然當(dāng)使用kg作為單位時(shí),顯然對(duì)模型的訓(xùn)練影響是不同的。
再舉一例來說,假如不同的特征的數(shù)值范圍不一樣,有的是0到0.1,有的是100到10000,那么,每個(gè)特征對(duì)應(yīng)的參數(shù)大小級(jí)別也會(huì)不一樣,在L1正則時(shí),我們是簡(jiǎn)單將參數(shù)的絕對(duì)值相加,因?yàn)樗鼈兊拇笮〖?jí)別不一樣,就會(huì)導(dǎo)致L1會(huì)對(duì)那些級(jí)別比較大的參數(shù)正則化程度高,那些小的參數(shù)都被忽略了。
就算不做正則化處理,建模前先對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理也是有好處的。進(jìn)行標(biāo)準(zhǔn)化后,我們得出的參數(shù)值的大小可以反應(yīng)出不同特征對(duì)label的貢獻(xiàn)度,使參數(shù)具有可解釋性。
這里注意一點(diǎn):有些需要保持?jǐn)?shù)據(jù)的原始量綱的情況下,不能對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化或者歸一化處理。例如,制作評(píng)分卡
而如何理解正則化方法呢?
我們?cè)谟?xùn)練模型時(shí),要最小化損失函數(shù),這樣很有可能出現(xiàn)過擬合的問題(參數(shù)過多,模型過于復(fù)雜),所以我么在損失函數(shù)后面加上正則化約束項(xiàng),轉(zhuǎn)而求約束函數(shù)和正則化項(xiàng)之和的最小值。
4. SparkMllib代碼實(shí)戰(zhàn)
0 數(shù)據(jù)準(zhǔn)備
// 原始數(shù)據(jù)
+---+---------------------+
| id| features|
+---+---------------------+
| 0|[1.0,0.5,-1.0]|
| 1| [2.0,1.0,1.0]|
| 2|[4.0,10.0,2.0]|
+---+---------------------+
代碼如下:
import org.apache.spark.ml.linalg.Vectors
val dataFrame = spark.createDataFrame(Seq(
(0, Vectors.dense(1.0, 0.5, -1.0)),
(1, Vectors.dense(2.0, 1.0, 1.0)),
(2, Vectors.dense(4.0, 10.0, 2.0))
)).toDF("id", "features")
dataFrame.show
4.1 Normalizer
Normalizer的作用范圍是每一行,使每一個(gè)行向量的范數(shù)變換為一個(gè)單位范數(shù)
作用對(duì)象:行
方法公式:
L1范數(shù)是指向量中各個(gè)元素絕對(duì)值之和
colX/(|col1|+|col2|...+|coln|)
L2范數(shù)是指向量各元素的平方和然后求平方根
colX/(|col1^2|+|col2^2|...+|coln^2|)^(1/2)
Ln無窮階范數(shù)最終趨近于絕對(duì)值最大的元素(x趨近于無窮)
colX/(|col1^x|+|col2^x|...+|coln^x|)^(1/x)
max(|col1|,|col2|...|coln|)
import org.apache.spark.ml.feature.Normalizer
// 正則化每個(gè)向量到1階范數(shù)
val normalizer = new Normalizer()
.setInputCol("features")
.setOutputCol("normFeatures")
.setP(1.0)
val l1NormData = normalizer.transform(dataFrame)
println("Normalized using L^1 norm")
l1NormData.show()
// 將每一行的規(guī)整為1階范數(shù)為1的向量,1階范數(shù)即所有值絕對(duì)值之和。
+---+--------------+------------------+
| id| features| normFeatures|
+---+--------------+------------------+
| 0|[1.0,0.5,-1.0]| [0.4,0.2,-0.4]|
| 1| [2.0,1.0,1.0]| [0.5,0.25,0.25]|
| 2|[4.0,10.0,2.0]|[0.25,0.625,0.125]|
+---+--------------+------------------+
// 正則化每個(gè)向量到無窮階范數(shù)
val lInfNormData = normalizer.transform(dataFrame, normalizer.p -> Double.PositiveInfinity)
println("Normalized using L^inf norm")
lInfNormData.show()
// 向量的無窮階范數(shù)即向量中所有值中的最大值
+---+--------------+--------------+
| id| features| normFeatures|
+---+--------------+--------------+
| 0|[1.0,0.5,-1.0]|[1.0,0.5,-1.0]|
| 1| [2.0,1.0,1.0]| [1.0,0.5,0.5]|
| 2|[4.0,10.0,2.0]| [0.4,1.0,0.2]|
+---+--------------+--------------+
4.2 StandardScaler
StandardScaler處理的對(duì)象是每一列,也就是每一維特征,將特征標(biāo)準(zhǔn)化為單位標(biāo)準(zhǔn)差或是0均值,或是0均值單位標(biāo)準(zhǔn)差。
作用對(duì)象:列
方法公式:(colX-avgValue)/stddev
主要有兩個(gè)參數(shù)可以設(shè)置:
withStd: 默認(rèn)為真。將數(shù)據(jù)標(biāo)準(zhǔn)化到單位標(biāo)準(zhǔn)差。
withMean: 默認(rèn)為假。是否變換為0均值。
StandardScaler需要fit數(shù)據(jù),獲取每一維的均值和標(biāo)準(zhǔn)差,來縮放每一維特征。
import org.apache.spark.ml.feature.StandardScaler
val scaler = new StandardScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
.setWithStd(true)
.setWithMean(false)
// Compute summary statistics by fitting the StandardScaler.
val scalerModel = scaler.fit(dataFrame)
// Normalize each feature to have unit standard deviation.
val scaledData = scalerModel.transform(dataFrame)
scaledData.show
// 將每一列的標(biāo)準(zhǔn)差縮放到1。
+---+--------------+--------------------------------------------+
|id |features |scaledFeatures |
+---+--------------+--------------------------------------------+
|0 |[1.0,0.5,-1.0]|[0.6546536707,0.093521952958,-0.65465367070]|
|1 |[2.0,1.0,1.0] |[1.30930734141,0.18704390591,0.65465367070] |
|2 |[4.0,10.0,2.0]|[2.61861468283,1.8704390591,1.30930734141] |
+---+--------------+--------------------------------------------+
4.3 MinMaxScaler
MinMaxScaler作用同樣是每一列,即每一維特征。將每一維特征線性地映射到指定的區(qū)間,通常是[0, 1]。
作用對(duì)象:列
方法公式:(colX-minValue)/(maxValue-minValue)
有兩個(gè)參數(shù)可以設(shè)置:
min: 默認(rèn)為0。指定區(qū)間的下限。
max: 默認(rèn)為1。指定區(qū)間的上限。
import org.apache.spark.ml.feature.MinMaxScaler
val scaler = new MinMaxScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
// Compute summary statistics and generate MinMaxScalerModel
val scalerModel = scaler.fit(dataFrame)
// rescale each feature to range [min, max].
val scaledData = scalerModel.transform(dataFrame)
println(s"Features scaled to range: [${scaler.getMin}, ${scaler.getMax}]")
scaledData.select("features", "scaledFeatures").show
// 每維特征線性地映射,最小值映射到0,最大值映射到1。
+--------------+--------------------------------------------+
|features |scaledFeatures |
+--------------+--------------------------------------------+
|[1.0,0.5,-1.0]|[0.0,0.0,0.0] |
|[2.0,1.0,1.0] |[0.33333333333,0.052631578947,0.66666666666]|
|[4.0,10.0,2.0]|[1.0,1.0,1.0] |
+--------------+--------------------------------------------+
4.4 MaxAbsScaler
MaxAbsScaler將每一維的特征變換到[-1, 1]閉區(qū)間上,通過除以每一維特征上的最大的絕對(duì)值,它不會(huì)平移整個(gè)分布,也不會(huì)破壞原來每一個(gè)特征向量的稀疏性。
作用對(duì)象:列
方法公式:colX/max(|colValue|)
import org.apache.spark.ml.feature.MaxAbsScaler
val scaler = new MaxAbsScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
// Compute summary statistics and generate MaxAbsScalerModel
val scalerModel = scaler.fit(dataFrame)
// rescale each feature to range [-1, 1]
val scaledData = scalerModel.transform(dataFrame)
scaledData.select("features", "scaledFeatures").show()
// 每一維的絕對(duì)值的最大值為[4, 10, 2]
+--------------+----------------+
| features| scaledFeatures|
+--------------+----------------+
|[1.0,0.5,-1.0]|[0.25,0.05,-0.5]|
| [2.0,1.0,1.0]| [0.5,0.1,0.5]|
|[4.0,10.0,2.0]| [1.0,1.0,1.0]|
+--------------+----------------+
5.總結(jié)
通過對(duì)SparkMllib特征工程中涉及的數(shù)值型數(shù)據(jù)的處理分析,總結(jié)如何對(duì)機(jī)器學(xué)習(xí)中的樣本和特征數(shù)據(jù)的分析和實(shí)踐,通過總結(jié)分析得到對(duì)應(yīng)結(jié)論,希望這部分知識(shí)能夠?qū)Τ醪綄W(xué)習(xí)SparkMllib但是對(duì)特征工程,尤其是數(shù)值型數(shù)據(jù)的特征工程理解存在問題的能夠起到作用。
推薦了解:
大數(shù)據(jù)培訓(xùn)課程
python+人工智能課程
北京校區(qū)