在大数据的学习过程中,总有很多小伙伴遇到不知如何调用Spark中的数据标准库,本文的核心这不是在于介绍「数据标准化」,也不是在于实现「Spark调用」,毕竟这些概念大家应该耳濡目染了,至于调用方法一搜一大堆。今天这个问题也是科多大数据的一名学员提出来的,估计有很多人也遇到类似的问题,一并分享在此,希望可以帮到大家。
首先,我们先看一下Spark要做「标准化」的输入数据样式。
// 原始数据
+---+-----------------+
| id| features |
+---+-----------------+
| 0 |[1.0,0.5,-1.0]|
| 1 | [2.0,1.0,1.0]|
| 2 |[4.0,10.0,2.0]|
+---+-----------------+
看到这,我就不想去用了,除了简单的DataFrame赋值,正常情况下的业务特征都是一张宽表,或者是其他特征工程的组合形式。
那有人会无聊去把数据的存储形式保存为向量型的呢?虽然也可以这样做,但是我觉得不太方便去回顾数据。
其次,在无奈之下,我在使用DataFrame和「标准化库」时,做了一个简单的优化,具体如下所示:
// 原始数据
Userid,Feature1,Feature2,Feature3
import sqlContext.implicits._
//需要进行数据标准化的特征(除Userid外)有:
val value = behavData.map(_.split(",")).map(record =>
{
var featureArray:Array[Double] = new Array[Double](3)
val userid = record(0)
val feature = ( for(i <- 1 until 3 ) yield record(i).toDouble ).toArray
val featureVector = Vectors.dense(feature)
(userid,featureVector)
}
).toDF("userid","featureSet")
这样的话,我就可以直接将「原始数据」转化为Spark标准化库所要求的样式了。
// 转化数据
Userid,[Feature1,Feature2,Feature3]
提醒一下,其他向量类型还不行,必须是import org.apache.spark.mllib.linalg.Vectors;
令人反感的「数据输入」解决了一半,我们再着手「数据输出」,尽量让后期的建模工作顺畅起来。
// 这是其中一种标准化方法的数据输出。
+------+----------------------+-------------------------------------------------------------------+
| id | features | scaledFeatures |
+------+-----------------------+------------------------------------------------------------------+
| 0 | [1.0,0.5,-1.0] | [0.654653670707,0.09352195,-0.654653670] |
| 1 | [2.0,1.0,1.0] | [1.3093073414159544,0.18704390,0.65465] |
| 2 | [4.0,10.0,2.0] | [2.618614682831909,1.87043905,1.309307] |
+-----+-------------------------+-----------------------------------------------------------------+
可能是我真的看不习惯,要说这结果输出的灵活性太差也不为过,所以我又做了一个简单的优化。
//将DataFrame转换成RDD再存储于HDFS上
val resultRDD = inputValue.rdd.map(record =>
{
val ouputResult = new StringBuilder()
ouputResult.append(record(0).toString()).append(",")
//调用字符串StrDealOne函数
StrDealOne(record(1).toString()).split(",").map(records =>
{
ouputResult.append(round(records.toDouble,4)).append(",")
}
)
//调用字符串StrDealTwo函数
StrDealTwo(ouputResult.toString())
}
)
其中
/**
* 字符串处理(替换特殊字符、去掉字符串末尾一位)
*/
def StrDealOne(InputValue:String):String = {
InputValue.replaceAll("\\(","").replaceAll("\\)","").replaceAll("\\[","").replaceAll("\\]","")
}
def StrDealTwo(InputValue:String):String = {
InputValue.substring(0, InputValue.toString().length()-1)
}
简单来说,就是让标准化后的数据恢复最初的Userid,Feature1,Feature2,Feature3格式,方便后期使用。
通过对数据「输入」和「输出」的简单操作,我在后期想将数值型的特征进行标准化时,就能很舒服去调用了。
通过以上的方法,就能轻松的调用Spark中的数据标准化库了