SparkML基于ALS,Kmeans实现用户聚类推荐

ALS(最小交替二乘法)概述

协同过滤算法,又称为“集体计算方法”,是一种基于群体用户或者物品的典型推荐算法,也是目前常用的推荐算法中最经典的算法。

在SparkML中,只有一种协同过滤模型——ALS,它替代了传统的基于物品(ItemCF)和基于用户(UserCF)的协同过滤算法。

ALS的意思是交替最小二乘法(Alternating Least Squares),它只是是一种优化算法的名字,被用在求解spark中所提供的推荐系统模型的最优解。spark中协同过滤的文档中一开始就说了,这是一个基于模型的协同过滤(model-based CF),其实它是一种近几年推荐系统界大火的隐语义模型中的一种。隐语义模型又叫潜在因素模型,它试图通过数量相对少的未被观察到的底层原因,来解释大量用户和产品之间可观察到的交互

KMeans概述

Kmeans算法是数据挖掘中一种常用的聚类方法,其基本思想和核心内容就是在算法开始时随机给定若干(K)个中心,按照最近距离原则将样本点分配到各个中心点,之后按平均法计算聚类集的中心点位置,从而重新确定新的中心点位置。这样不断地迭代下去直至聚类集内的样本满足阈值为止。

ALS+KMeans 实现基于用户隐语义特征向量的聚类

ALS算法的核心,其实是将一个用户评分矩阵 W® [r为这个矩阵的rank] 近似分解为两个rank小于用户评分矩阵W的矩阵 U(n)和V(m),且n<=r,m<=r。最后对U VT做笛卡尔积,取推荐的前N项。

KMeans算法,则是根据随机的中心点,按照用户特征向量聚类。

在SparkML中,使用ALS模型,可以得到基于矩阵W所分解而成的用户隐语义特征向量userFactor和物品隐语义特征向量Itemfactor,我们可以使用KMeans模型,对两个特征向量进行聚类。

基于隐语义用户向量的用户推荐

 import spark.implicits._
    //todo 使用als模型获取基于评分的 用户\物品 特征向量
    //获取数据
    val rating = spark.table("dw.dw_user_rating")
      .select($"gid", $"game_id", $"rating")
    //利用StringIndexer获取映射模型
    val index_1 = new StringIndexer().setInputCol("gid").setOutputCol("gid_indexed").setHandleInvalid("keep")
    val index_2 = new StringIndexer().setInputCol("game_id").setOutputCol("game_id_indexed").setHandleInvalid("keep")
    // 获取管道模型
    val stringIndexers = new Pipeline().setStages(Array(index_1, index_2)).fit(rating)
    val indexDF = stringIndexers.transform(rating)
    //数据处理
    val transData = indexDF.select($"gid_indexed".cast("int"), $"game_id_indexed".cast("int"), $"rating".cast("float"))
      .toDF("gid_indexed", "game_id_indexed", "rating")
    //ALS模型训练
    val alsObj = new ALS().setRank(10).setMaxIter(10).setRegParam(0.01).setUserCol("gid_indexed").setItemCol("game_id_indexed").setRatingCol("rating")
    val alsModel = alsObj.fit(transData)
    //todo 
    //用户特征向量数据处理
    val userFactors = alsModel.userFactors
    //获取到的用户特征向量为array[Float]类型,需要转换成DenseVector[Double]类
    val inputDF = userFactors.rdd.map(row => {
      (row.getAs[Int]("id"), Vectors.dense(row.getAs[Seq[Float]]("features").toArray.map(_.toDouble)))
    }).toDF("id", "features")
    //Kmeans模型训练
    val kmsObj = new KMeans().setFeaturesCol("features").setK(1000).setMaxIter(10)
    val kmsModel = kmsObj.fit(inputDF)
    //模型中心点集合
    val clusterCenters = kmsModel.clusterCenters
    //计算每个用户特征向量到中心点的欧式距离,以离中心点最近的数据作为推荐模板
    val df = kmsModel.transform(inputDF).rdd.map(row => {
      val feature = row.getAs[DenseVector]("features").toArray
      var minDis: Double = Double.MaxValue
      var center = Vectors.zeros(0)
      clusterCenters.foreach(v => {
        val dis = v.toArray.zip(feature).map(t => (t._1 - t._2) * (t._1 - t._2)).reduce(_ + _)
        if (minDis >= dis) {
          center = v
          minDis = dis
        }
      })
      (row.getAs[Int]("id"), row.getAs[DenseVector]("features").toArray.map(_.toFloat), row.getAs[Int]("prediction"), minDis, center)
    }).toDF("id", "features", "prediction", "min_dis", "center")
    //数据处理
    val refDF = df.select($"id", $"features", $"min_dis", $"prediction", $"center", row_number() over Window.partitionBy($"prediction").orderBy(asc("min_dis")) as "row_number")
      .where($"row_number" === 1)
    val test = refDF.select($"id", $"features")
    //ALSModel中的userFactor变量为私有变量,因此需要利用反射机制修改
    val field = classOf[ALSModel].getDeclaredField("userFactors")
    println(field.getName)
    field.setAccessible(true)
    field.set(alsModel, test)
    //result test
    val test_1 = alsModel.recommendForAllUsers(10).join(refDF.select($"id" as "gid", $"prediction"), Seq("gid"), "left")
      .select($"prediction", $"recommendations")
      .join(df.select($"id", $"prediction"), Seq("prediction"), "right").select($"id" as "gid", $"recommendations" as "test_rec", $"prediction")
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值