更新時間:2019年09月18日17時20分 來源:傳智播客 瀏覽次數(shù):
在SparkMllib中主要分為特征抽取、特征轉(zhuǎn)化、特征選擇,特別是在特征轉(zhuǎn)化方面是從一個DataFrame轉(zhuǎn)化為另外一個DataFrame,在數(shù)值型數(shù)據(jù)處理的時候我們對機器學習數(shù)據(jù)集中的樣本和特征部分進行單獨的處理,這里就涉及對樣本的正則化操作和數(shù)值型特征的歸一化和標準化的方法,今天就帶大家理解這一部分的思考和認識。
1.數(shù)據(jù)歸一化
什么是數(shù)據(jù)的歸一化?
答:數(shù)據(jù)的標準化是將數(shù)據(jù)按比例縮放,使之落入一個小的特定區(qū)間。在某些比較和評價的指標處理中經(jīng)常會用到,去除數(shù)據(jù)的單位限制,將其轉(zhuǎn)化為無量綱的純數(shù)值,便于不同單位或量級的指標能夠進行比較和加權(quán)。其中最典型的就是數(shù)據(jù)的歸一化處理,即將數(shù)據(jù)統(tǒng)一映射到[0,1]區(qū)間上。
為什么對數(shù)據(jù)歸一化處理?
我們在對數(shù)據(jù)進行分析的時候,往往會遇到單個數(shù)據(jù)的各個維度量綱不同的情況,比如對房子進行價格預測的線性回歸問題中,我們假設房子面積(平方米)、年代(年)和幾居室(個)三個因素影響房價,其中一個房子的信息如下:
面積(S):150 平方米
年代(Y):5 年
這樣各個因素就會因為量綱的問題對模型有著大小不同的影響,但是這種大小不同的影響并非反應問題的本質(zhì)。
為了解決這個問題,我們將所有的數(shù)據(jù)都用歸一化處理至同一區(qū)間內(nèi)。
2.數(shù)據(jù)標準化
什么是標準化(StandardScaler)?
訓練集中某一列數(shù)值特征(假設是第i列)的值縮放成均值為0,方差為1的狀態(tài)。標準化之后,數(shù)據(jù)的范圍并不一定是0-1之間,數(shù)據(jù)不一定是標準正態(tài)分布,因為標準化之后數(shù)據(jù)的分布并不會改變,如果數(shù)據(jù)本身是正態(tài)分布,那進行標準化之后就是標準正態(tài)分布。
(1)歸一化和標準化的相同點都是對某個特征(column)進行縮放(scaling)而不是對某個樣本的特征向量(row樣本數(shù)據(jù))進行縮放。對行進行縮放是毫無意義的。比如三列特征:身高、體重、血壓。每一條樣本(row)就是三個這樣的值,對這個row無論是進行標準化還是歸一化都是無意義的,因為你不能將身高、體重和血壓混到一起去。
(2)標準化/歸一化的好處
提升模型精度:基于距離的算法,例如Kmeans、KNN等,各個特征的量綱直接決定了模型的預測結(jié)果。舉一個簡單的例子,在KNN中,我們需要計算待分類點與所有實例點的距離。假設每個實例點(instance)由n個features構(gòu)成。如果我們選用的距離度量為歐式距離,如果數(shù)據(jù)預先沒有經(jīng)過歸一化,那么那些絕對值大的features在歐式距離計算的時候起了決定性作用。對于PCA,如果沒有對數(shù)據(jù)進行標準化,部分特征的所占的信息可能會虛高。
提升收斂速度:例如,對于linear model來說,數(shù)據(jù)歸一化后,最優(yōu)解的尋優(yōu)過程明顯會變得平緩,更容易正確的收斂到最優(yōu)解。對于SVM標準化之后梯度下降的速度加快。
3.標準化和歸一化的對比分析
(1)標準化/歸一化的對比分析
首先明確,在機器學習中,標準化是更常用的手段。
MinMaxScaler對異常值非常敏感。例如,比如三個樣本,某個特征的值為1,2,10000,假設10000這個值是異常值,用歸一化的方法后,正常的1,2就會被“擠”到一起去。在PCA,聚類,邏輯回歸,支持向量機,神經(jīng)網(wǎng)絡這些算法中,StandardScaler往往是最好的選擇。
當數(shù)據(jù)需要被壓縮至一個固定的區(qū)間時,我們使用MinMaxScaler.
(2)在邏輯回歸中需要使用標準化么?
如果你不用正則,那么,標準化并不是必須的,如果你用正則,那么標準化是必須的。為什么呢?因為不用正則時,我們的損失函數(shù)只是僅僅在度量預測與真實的差距,加上正則后,我們的損失函數(shù)除了要度量上面的差距外,還要度量參數(shù)值是否足夠小。而參數(shù)值的大小程度或者說大小的級別是與特征的數(shù)值范圍相關(guān)的。
舉一例來說,我們預測身高,體重用kg衡量時,訓練出的模型是: 身高 = x*體重+y*父母身高,X是我們訓練出來的參數(shù)。當我們的體重用噸來衡量時,x的值就會擴大為原來的1000倍。在上面兩種情況下,都用L1正則的話,顯然當使用kg作為單位時,顯然對模型的訓練影響是不同的。
再舉一例來說,假如不同的特征的數(shù)值范圍不一樣,有的是0到0.1,有的是100到10000,那么,每個特征對應的參數(shù)大小級別也會不一樣,在L1正則時,我們是簡單將參數(shù)的絕對值相加,因為它們的大小級別不一樣,就會導致L1會對那些級別比較大的參數(shù)正則化程度高,那些小的參數(shù)都被忽略了。
就算不做正則化處理,建模前先對數(shù)據(jù)進行標準化處理也是有好處的。進行標準化后,我們得出的參數(shù)值的大小可以反應出不同特征對label的貢獻度,使參數(shù)具有可解釋性。
這里注意一點:有些需要保持數(shù)據(jù)的原始量綱的情況下,不能對數(shù)據(jù)進行標準化或者歸一化處理。例如,制作評分卡
而如何理解正則化方法呢?
我們在訓練模型時,要最小化損失函數(shù),這樣很有可能出現(xiàn)過擬合的問題(參數(shù)過多,模型過于復雜),所以我么在損失函數(shù)后面加上正則化約束項,轉(zhuǎn)而求約束函數(shù)和正則化項之和的最小值。
4. SparkMllib代碼實戰(zhàn)
0 數(shù)據(jù)準備
// 原始數(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的作用范圍是每一行,使每一個行向量的范數(shù)變換為一個單位范數(shù)
作用對象:行
方法公式:
L1范數(shù)是指向量中各個元素絕對值之和
colX/(|col1|+|col2|...+|coln|)
L2范數(shù)是指向量各元素的平方和然后求平方根
colX/(|col1^2|+|col2^2|...+|coln^2|)^(1/2)
Ln無窮階范數(shù)最終趨近于絕對值最大的元素(x趨近于無窮)
colX/(|col1^x|+|col2^x|...+|coln^x|)^(1/x)
max(|col1|,|col2|...|coln|)
import org.apache.spark.ml.feature.Normalizer
// 正則化每個向量到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ù)即所有值絕對值之和。
+---+--------------+------------------+
| 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]|
+---+--------------+------------------+
// 正則化每個向量到無窮階范數(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處理的對象是每一列,也就是每一維特征,將特征標準化為單位標準差或是0均值,或是0均值單位標準差。
作用對象:列
方法公式:(colX-avgValue)/stddev
主要有兩個參數(shù)可以設置:
withStd: 默認為真。將數(shù)據(jù)標準化到單位標準差。
withMean: 默認為假。是否變換為0均值。
StandardScaler需要fit數(shù)據(jù),獲取每一維的均值和標準差,來縮放每一維特征。
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
// 將每一列的標準差縮放到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]。
作用對象:列
方法公式:(colX-minValue)/(maxValue-minValue)
有兩個參數(shù)可以設置:
min: 默認為0。指定區(qū)間的下限。
max: 默認為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ū)間上,通過除以每一維特征上的最大的絕對值,它不會平移整個分布,也不會破壞原來每一個特征向量的稀疏性。
作用對象:列
方法公式: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()
// 每一維的絕對值的最大值為[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é)
通過對SparkMllib特征工程中涉及的數(shù)值型數(shù)據(jù)的處理分析,總結(jié)如何對機器學習中的樣本和特征數(shù)據(jù)的分析和實踐,通過總結(jié)分析得到對應結(jié)論,希望這部分知識能夠?qū)Τ醪綄W習SparkMllib但是對特征工程,尤其是數(shù)值型數(shù)據(jù)的特征工程理解存在問題的能夠起到作用。
推薦了解:
大數(shù)據(jù)培訓課程
python+人工智能課程