文章目录
前言:
很多人还在实用RDD的相关API,为跟上“未来”,咱讨论下DataFrame版的相关API。
MLlib 的基于 RDD 的 API 现在处于维护状态。
从 Spark 2.0 开始, spark.mllib 包中的基于 RDD 的 API 已经进入了维护模式。Spark 的主要的机器学习 API 现在是 spark.ml 包中的基于 DataFrame 的 API 。
有什么影响?
MLlib 仍将支持基于 RDD 的 API ,在 spark.mllib 中有 bug 修复。
MLlib 不会为基于 RDD 的 API 添加新功能。
在 Spark 2.x 发行版本中, MLlib 将向基于 DataFrames 的 API 添加功能,以达到与基于 RDD 的 API 的功能奇偶校验。
在达到功能奇偶校验(大概估计为 Spark 2.3 )之后,基于 RDD 的 API 将被弃用。
预计将在 Spark 3.0 中删除基于 RDD 的 API 。
为什么 MLlib 切换到基于 DataFrame 的 API ?
DataFrames 提供比 RDD 更加用户友好的 API 。 DataFrames 的许多好处包括 Spark Datasources,SQL/DataFrame 查询,Tungsten 和 Catalyst 优化以及跨语言的统一 API 。
用于 MLlib 的基于 DataFrame 的 API 为 ML algorithms (ML 算法)和跨多种语言提供了统一的 API 。
DataFrames 便于实际的 ML Pipelines (ML 管道),特别是 feature transformations (特征转换)。有关详细信息,请参阅 Pipelines 指南 。
##正文
在将数据“喂”给模型之前,预处理中很重要的一步是去除冗余数据。
关于计算相关系数前是否需要将数据标准化:
大部分人表示“可以不用,因为相关系数本身就是一个标准化的统计量,协方差可以用来表示变量间共同变化的程度,而相关系数是协方差标准化后得到的统计量。”
我还没求证,等放上几天,我再比较不同结果得下结论。
- 想想含有n个特征的数据集,计算一个n X n的相关系数矩阵【我只计算了对角线的一侧,因为X与Y和Y与X的相关系数是相等的】,并将结果保存在Double二维数组中。可以看到,部分列之间的相关性确实很高。但别急,现在还不能删,因为我们还不知道删除哪一个变量更为合理。
- 对数组中的数处理为绝对值之后复制一份,对副本进行排序(NaN之前已经被处理为0),每次取复制的数组中的第一个值(前提是大于阈值0.8);在二维数组中找到对应的两个变量记为indexX和indexY
- 计算indexX和其他所有变量的相关系数的绝对值之和,记为sumX;同理,对indexY,记为sumY。比较,删除sum值较大的那一个变量(对于DataFrame删)
- 重复2-3步骤,直到处理完复制的数组中的所有大于阈值的值
- 保存清洗过后的数据
代码
其实不想贴代码,因为代码不“漂亮”,有较多的for循环。一方面是对scala还不能灵活运用,一方面没找到DataFrame中直接对变量矩阵进行运算得出相关系数矩阵的方法。所以就自己用for循环造了。
package main.scala.firstput
import org.apache.log4j.{
Level, Logger}
import org.apache.spark.sql.{
DataFrame, SparkSession}
/**
* @author 王海[https://github.com/AtTops]
* package main.scala.firstput
* description 计算相关性矩阵,将大于阈值0.8的挑选删除
* Date 2018/1/2 9:35
* Version V1.0
*/
object GetCorrelationMartix {
var myTrainCsvPath: String = "yourpath"
var secondTrainCsvPath: String = "yourpath"
/**
* 使用DataFrameStatFunctions中的API
* TODO:参考mlib中的correlationExample.scala,修改为矩阵运算
*/
def correlationAndCleanAgain_w(columnNames: Array[String], dataFrame: DataFrame): DataFrame = {
// 计算一个n X n的相关系数矩阵【我只计算了对角线的一侧】,并将结果保存在Double二维数组中
val storeCorrsMatrix = Array.ofDim[Double](columnNames.length, columnNames.length) // 使用ofDim创建二维数组
var tempDf: DataFrame = dataFrame
for (i <- 0 until columnNames.length - 1) {
// 我们仅计算矩阵对角线一侧就行
// println(f"${columnNames(i)}%5s 与其他列-------------------------------------------") // 这里的f插值没有起作用
for (j <- i + 1 until columnNames.length) {
var corrValue: Double = dataFrame.stat.corr(columnNames(i), columnNames(j))
if (corrValue < 0)
corrValue = corrValue.abs // 处理为绝对值
else if (corrValue.isNaN)
corrValue = 0 // NaN处理为0
/* if (corrValue > 0.8)
println(s"${columnNames(i)}与${columnNames(j)}的相关系数值为:$corrValue") // s字符串插值器,scala2.10添加*/
storeCorrsMatrix(i)(j) = corrValue
}
}
println("它应该是0:" + storeCorrsMatrix(5)(5) + " ;它应该是0.9645:" + storeCorrsMatrix(22)(23)) // 简单验证
val corrsMatrixClong: Array[Double] = storeCorrsMatrix.flatten.sortWith(_ > _) // 二维数组按行拼接为一维数组,然后从小到大排序
// storeCorrsMatrix.copyToArray(corrsMatrixClong, 0)
/*println("storeCorrs数组的长度为:" + storeCorrs.length) // 276(23+22+21+...1)
println("front_track与rear_track的相关系数值为:" + storeCorrs(storeCorrs.length-1))*/
// println(corrsMatrixClong.mkString(" "))
println(corrsMatrixClong.length) // 576=24*24
// 每次取复制的数组中的第一个值(前提是大于阈值0.8);在二维数组中找到对应的两个变量的位置记为valueX和valueY
// 为了简便,我取的下标,因为我这里就8个大于阈值0.8的数
for (i <- 0 to 7) {
val indexArray: Array[Int] = findIndexByValue_w(storeCorrsMatrix, corrsMatrixClong(i))
val indexX = indexArray(0