Spark:特征处理之数据标准化
数据标准化
先定义一个df
import org.apache.spark.ml.linalg.Vectors
val df = 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")
df.show
+---+--------------+
| id| features|
+---+--------------+
| 0|[1.0,0.5,-1.0]|
| 1| [2.0,1.0,1.0]|
| 2|[4.0,10.0,2.0]|
+---+--------------+
再介绍四种数据标准化方法
Normalizer(行缩放)
处理的对象是每一行,也就是每一组特征:将行向量的范数变换为单位范数(范数的阶通过参数指定)。
变换前后向量方向不变,也就是向量各维度的比例不变。
实际就是将每一组行向量的各个维度除以其指定阶的范数值(缩放)。
如其中一组行向量为[a, b, c],它的n阶范数值为m,则用setP(n)
设置参数后,标准化得到向量[a/m, b/m, c/m]。
import org.apache.spark.ml.feature.Normalizer
//正则化行向量的1阶范数为一个单位,向量的1阶范数等于向量每个维度的绝对值的和。
//默认为2阶范数。即所有维度的平方和再开方的值。(欧几里德距离)
val normalizer = new Normalizer()
.setInputCol("features")
.setOutputCol("normFeature")
.setP(1)
normalizer.transform(df).show
+---+--------------+------------------+
| id| features| normFeature|
+---+--------------+------------------+
| 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]|
+---+--------------+------------------+
补充:
- 向量n阶范数等于向量各维度的绝对值的n次方之和,再开n次方。
- 正无穷范数等于向量各维度绝对值的最大值,负无穷范数等于各维度绝对值最小值。
StandardScaler(列缩放、平移)
处理的对象是每一列,也就是每一维特征:将每一维的特征列向量标准化为样本标准差为1,或者平均值为0。
这里求样本标准差的公式为:
主要有两个参数可以设置:
-
withStd
: 默认为true。将数据标准化到单位标准差。
实际就是将每维特征的各特征值除以这一维特征的标准差(缩放)。
如其中一组特征列向量为[a, b, c],它的样本标准差为m,则用setWithStd(true)
设置参数后,标准化得到向量[a/m, b/m, c/m]。 -
withMean
: 默认为false。是否变换为0均值。
实际就是将每维特征的各特征值减去这一维特征的平均值(平移)。
如其中一组特征列向量为[a, b, c],它的平均值为m,则用用setWithMean(true)
设置参数后,标准化得到向量[a-m, b-m, c-m]。
若两个参数都设置为true,则可以先平移再缩放(因为平移不会改变样本的标准差)。
StandardScaler需要fit数据,获取每一维的均值和标准差,再变换每一维的特征。
import org.apache.spark.ml.feature.StandardScaler
val scaler = new StandardScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
.setWithStd(true)
.setWithMean(false)
val scalerModel = scaler.fit(df)
scalerModel.transform(df).show(false)
+---+--------------+------------------------------------------------------------+
|id |features |scaledFeatures |
+---+--------------+------------------------------------------------------------+
|0 |[1.0,0.5,-1.0]|[0.6546536707079772,0.09352195295828244,-0.6546536707079771]|
|1 |[2.0,1.0,1.0] |[1.3093073414159544,0.1870439059165649,0.6546536707079771] |
|2 |[4.0,10.0,2.0]|[2.618614682831909,1.870439059165649,1.3093073414159542] |
+---+--------------+------------------------------------------------------------+
MinMaxScaler(列先缩放后平移)
处理的对象是每一列:将每一维特征线性地映射到指定的区间,默认是[0, 1]。
实际就是将每维特征的各特征值进行先缩放再平移,缩放比例是原向量的跨度(最大值减最小值)除以(max-min),平移距离为缩放完之后所得中间向量的元素最小值减去min。
主要有两个参数可以设置:
min
: 默认为0。指定区间的下限。max
: 默认为1。指定区间的上限。
需要fit数据,获取每一维的最大值和最小值,再变换每一维的特征。
import org.apache.spark.ml.feature.MinMaxScaler
val scaler = new MinMaxScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
.setMin(0)
.setMax(1)
val scalerModel = scaler.fit(df)
scalerModel.transform(df).show(false)
+---+--------------+-----------------------------------------------------------+
|id |features |scaledFeatures |
+---+--------------+-----------------------------------------------------------+
|0 |[1.0,0.5,-1.0]|[0.0,0.0,0.0] |
|1 |[2.0,1.0,1.0] |[0.3333333333333333,0.05263157894736842,0.6666666666666666]|
|2 |[4.0,10.0,2.0]|[1.0,1.0,1.0] |
+---+--------------+-----------------------------------------------------------+
MaxAbsScaler(列缩放)
处理的对象是每一列:将每一维的特征线性变换到[-1, 1]闭区间上。
实际就是通过将每一维特征值除以列向量上的最大值的绝对值(缩放),它不会平移,所以不会破坏原来每一组行特征向量的稀疏性。
此变换没有额外参数,需要fit数据,获取每一维的最大值,再变换每一维的特征。
import org.apache.spark.ml.feature.MaxAbsScaler
val scaler = new MaxAbsScaler()
.setInputCol("features")
.setOutputCol("scaledFeatures")
val scalerModel = scaler.fit(df)
scalerModel.transform(df).show(false)
+---+--------------+----------------+
|id |features |scaledFeatures |
+---+--------------+----------------+
|0 |[1.0,0.5,-1.0]|[0.25,0.05,-0.5]|
|1 |[2.0,1.0,1.0] |[0.5,0.1,0.5] |
|2 |[4.0,10.0,2.0]|[1.0,1.0,1.0] |
+---+--------------+----------------+