Spark ML计算皮尔逊相似度案例

Spark ML 计算两用户间的皮尔逊相似度

    • 功能说明
    • 数据格式及说明
    • 设计思路
      • Spark ML 计算皮尔逊相关系数
    • 代码(Scala)

功能说明

该程序根据不同用户对不同电影的评分情况,通过Spark MLCorrelation.corr函数计算用户之间的皮尔逊相关矩阵。

数据格式及说明

该数据为模拟数据。

X   A:5.0,B:1.0,C:2.0,D:0
Y   A:3.0,B:1.0,C:2.0,D:3.00
  1. 其中X、Y分别代表两个用户
  2. A-D代表电影名称,电影名后面代表该用户的评分

注意:实际情况下数据并没有这么理想,所以本次测试仅供学习。

设计思路

Spark ML 计算皮尔逊相关系数

Spark 计算皮尔逊相关系数使用的是Correlation.corr()函数,函数具体使用方法可参考之前博客。

  • 使用皮尔逊相关系数公式计算XY的相关系数,用来验证代码的正确性
    在这里插入图片描述

代码(Scala)

object Pearson {
	def main(args: Array[String]): Unit = {
		// 屏蔽日志
		Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
		Logger.getLogger("org.apache.jetty.server").setLevel(Level.OFF)

		val spark = SparkSession
			.builder()
			.master("local[*]")
			.appName(Demo03.getClass.getName)
			.getOrCreate()

		import spark.implicits._

		// 将数据加载为DataFrame
		val data: DataFrame = spark.read.format("text").load("/Users/mashikang/IdeaProjects/spark-mllib/src/main/resources/input/test")

		/**
		 * 将数据清洗格式并创建表结构
 		 */
		val frame = data.select($"value")
			.map(_.getAs[String]("value"))
			.rdd
			.flatMap(line => {
				val strs = line.split("\\s+")
				val movie = strs(1).split(",")
				val tuples = movie.map(m => {
					val strings = m.split(":")
					(strs(0), strings(0), strings(1).toDouble)
				})
				tuples.toList
			})
			.toDF("user", "movie", "score")

		// 展示清洗数据 并创建该表的视图
		println("清洗后数据:")
		frame.show()
		frame.createOrReplaceTempView("user")

		/**
		 * 将数据进行 行、列颠倒
		 */
		val sql =
			"""
			  |  select movie,
			  |  max(case user when 'X' then score else 0 end) as X,
			  |  max(case user when 'Y' then score else 0 end) as Y
			  |  from user group by movie
			""".stripMargin

		println("行转列后:")
		spark.sql(sql).show()

		/**
		 * 将数据封装为向量
		 */
		val vectors = spark.sql(sql)
			.drop("movie")
			.map(row => {
				val list = new ListBuffer[Double]
				for (i <- 0 until row.size) {
					list.+=(row.getDouble(i))
				}
				list.toArray
			})
			.rdd
			.map(Vectors.dense(_))

		// 将rdd中的向量放入Seq中
		val seq: Seq[linalg.Vector] = vectors.collect().toSeq
		val df = seq.map(Tuple1.apply).toDF("features")

		// 计算df features列的相关性
		val Row(coef: Matrix) = Correlation.corr(df, "features").head
		println(s"用户X和Y的Pearson相关矩阵为:\n $coef")

	}
}
  • 结果
清洗后数据:
+----+-----+-----+
|user|movie|score|
+----+-----+-----+
|   X|    A|  5.0|
|   X|    B|  1.0|
|   X|    C|  2.0|
|   X|    D|  0.0|
|   Y|    A|  3.0|
|   Y|    B|  1.0|
|   Y|    C|  2.0|
|   Y|    D|  3.0|
+----+-----+-----+

行转列后:
+-----+---+---+
|movie|  X|  Y|
+-----+---+---+
|    B|1.0|1.0|
|    D|0.0|3.0|
|    C|2.0|2.0|
|    A|5.0|3.0|
+-----+---+---+

数据封装为向量后:
[5.0,3.0]
[2.0,2.0]
[0.0,3.0]
[1.0,1.0]
20/07/08 17:47:39 WARN BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS
20/07/08 17:47:39 WARN BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeRefBLAS
用户X和Y的Pearson相关矩阵为:
 1.0                 0.3223291856101522  
0.3223291856101522  1.0                 

该程序打印为一个2*2的的相关矩阵,矩阵的元素是由元数据单个向量的长度决定的。矩阵11位置为X用户与X用户的相关系数,22位置为Y用户与Y用户的相关系数,1221位置分别代表X、Y和Y、X的相关系数,明显可以看出X、Y的相关系数与我们上面算的基本一致。

如果我们的用户为三个,也就是说行转列并且封装为向量后,每个向量的长度为3,那么皮尔逊相关矩阵的大小就为3*3

你可能感兴趣的:(Spark,机器学习,大数据)