Spark -- 数据的特征缩放(Feature scaling)
特征缩放:有的叫数据归一化,有的叫数据标准化,其实两者有着一些差别,但是大多数时候都是表达的一个意思,它的目的就是使数据缩小范围。具体的介绍请参照维基百科。
在spark中就提供了常用的这几种特征缩放方法
- Normalizer
- StandardScaler
- MinMaxScaler
- MaxAbsScaler
// 使用 StandardScaler 标准化: 计算公式 X'=(Xi-u)/δ
val scaler = new StandardScaler()
.setInputCol("features") .setOutputCol("scaledfts")
.setWithStd(true) .setWithMean(true)
// 创建一个 dataframe
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.printSchema()
val scalerModel = scaler.fit(dataFrame)
val scaledData = scalerModel.transform(dataFrame)
scaledData.show(truncate = false)
spark提供的方法要求输入的数据类型是 Vector格式
root
|-- id: integer (nullable = false)
|-- features: vector (nullable = true)
结果查看
+---+--------------+--------------------------------------------------------------+
|id |features |scaledfts |
+---+--------------+--------------------------------------------------------------+
|0 |[1.0,0.5,-1.0]|[-0.8728715609439696,-0.6234796863885498,-1.0910894511799618] |
|1 |[2.0,1.0,1.0] |[-0.21821789023599245,-0.5299577334302673,0.21821789023599242]|
|2 |[4.0,10.0,2.0]|[1.0910894511799618,1.1534374198188169,0.8728715609439697] |
+---+--------------+--------------------------------------------------------------+
很多时候我们拿到的数据的特征不是向量形式。因此在做标准化之前需要将各个特征合并转化成向量。可以有两种方式解决 (本案例以鸢尾花数据集为例)
方法一 spark提供的API
val iris = spark.read.option("header", true)
.option("inferSchema", true)
.csv("F:/DataSource/iris.csv")
val fts = Array("sepalLength", "sepalWidth", "petalLength", "petalWidth")
// 将多个列合并成向量列的特性转换器
val amountVectorAssembler: VectorAssembler = new VectorAssembler()
.setInputCols(fts)
.setOutputCol("features")
val df1 = amountVectorAssembler.transform(iris)
.select($"class", $"features")
scaler.fit(df1).transform(df1).show(3 )
方法二 自定义函数
// 自定义函数合并列并转化为向量
val vectorUdf = udf((fts: Seq[Double]) => {
Vectors.dense(fts.toArray)
})
val df2 = iris.withColumn("features",
vectorUdf(array("sepalLength", "sepalWidth", "petalLength", "petalWidth")))
.select($"class",$"features")
scaler.fit(df2).transform(df2).show(3)
两个方法的结果是一致的
+-----------+-----------------+--------------------+
| class| features| scaledfts|
+-----------+-----------------+--------------------+
|Iris-setosa|[5.1,3.5,1.4,0.2]|[-0.8976738791967...|
|Iris-setosa|[4.9,3.0,1.4,0.2]|[-1.1392004834649...|
|Iris-setosa|[4.7,3.2,1.3,0.2]|[-1.3807270877331...|
+-----------+-----------------+--------------------+
剩下的几种方式就不再一一介绍,用法基本一致,具体的使用方法,适用范围以及计算方法可以参照spark官方提供的文档以及代码;也可以查看相关资料了解更详细的信息。