一.簡介
計算兩個系列數據之間的相關性是“統計”中的常見操作。spark.ml 提供了很多系列中的靈活性,計算兩兩相關性。目前支持的相關方法是Pearson和Spearman的相關。
Correlation 使用指定的方法爲向量的輸入數據集計算相關矩陣。輸出將是一個DataFrame,其中包含向量列的相關矩陣。
二.代碼實戰
import spark.implicits._
val data = Seq(
Vectors.sparse(4, Seq((0, 7.0), (3, -2.0))), // 稀疏向量,等價於dense(7.0, 0.0, 0.0, -2.0)
Vectors.dense(0.0, 5.0, 3.0, 3.0), // 稠密向量
Vectors.dense(0.0, 7.0, 5.0, 8.0),
Vectors.sparse(4, Seq((0, 9.0), (3, 1.0)))
)
/**
* NaN : not a number
*/
val df = data.map(Tuple1.apply).toDF("features")
df.show(false)
val Row(coeff : Matrix) = Correlation.corr(df, "features").head // 使用默認的Pearson
println(coeff)
/**
* 對於Spearman,是排名相關性,我們需要爲每個列創建一個RDD [Double]並對其進行排序,以便檢索排名,
* 然後將這些列重新連接到RDD [Vector]中,這是相當昂貴的。 在使用`method =“ spearman”`調用corr之前,
* 請緩存輸入數據集,以避免重新計算公共譜系。
*/
val Row(coeff2 : Matrix) = Correlation.corr(df, "features", "spearman").head // 指定相關類型
println(coeff2)
spark.stop()
}
}
完整代碼及相關Spark程序查看Github:Spark代碼實戰
三.執行結果
測試數據:
生成的相關性矩陣:
1.使用默認pearson
2.使用spearman
- 根據生成的相關性矩陣可知,兩者的差距不大,一般情況下使用默認的相關性方法參加即可。
- 第二和第三個向量相關性最高,其次是第三個向量,第一個向量相關性較低,原因應該是該向量存在負數。在進行相關性之前可以考慮使用歸一化以降低此類影響。
四.源碼分析
@Since("2.2.0")
@Experimental
object Correlation {
@Since("2.2.0")
def corr(dataset: Dataset[_], column: String, method: String): DataFrame = {
val rdd = dataset.select(column).rdd.map {
case Row(v: Vector) => OldVectors.fromML(v)
}
val oldM = OldStatistics.corr(rdd, method)
val name = s"$method($column)"
val schema = StructType(Array(StructField(name, SQLDataTypes.MatrixType, nullable = false)))
dataset.sparkSession.createDataFrame(Seq(Row(oldM.asML)).asJava, schema)
}
/**
* Compute the Pearson correlation matrix for the input Dataset of Vectors.
*/
@Since("2.2.0")
def corr(dataset: Dataset[_], column: String): DataFrame = {
corr(dataset, column, "pearson")
}
}
從源代碼上可以看出默認是使用pearson作爲相關性計算的,而且具體計算的邏輯是在OldStatistics.corr(rdd, method)中實現的。
根據參數的詳細註釋可知:
- 第一個參數:一個dataset或dataframe。
- 第二個參數:列的名稱,需要爲其計算相關係數。 必須是數據集的一列,並且必須包含Vector對象。
- 第三個參數:指定用於計算相關性的方法。包括
pearson
(default),spearman
。 - 返回值:包含向量列的相關矩陣的dataframe。 該dataframe包含單行和單列名稱。
- 違法參數異常IllegalArgumentException:如果該列不是數據集中的有效列,或者該列的內容不是Vector類型。