Spark推荐系统实现

代码实现如下:

使用电影数据集进行训练模型

package mllib.Collaborativefiltering
import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.SparkSession
import org.apache.spark.mllib.recommendation.{ALS, Rating}
import org.apache.spark.rdd.RDD
/**
  * Created by win7 on 2018/10/23.
  *
  * 使用协同过滤实现spark mllib推荐功能
  * 数据集:电影数据集
  *
  */
object moivelensALStrain {
  val numRecommender = 10
  """
    |参数设置:
    |numBlocks:是用于并行计算的块数(设置为-1以自动配置)。
    |rank:是模型中潜在因子的数量。
    |iterations:是要运行的ALS的迭代次数。ALS通常在20次或更少次迭代中收敛到合理的解决方案。
    |lambda:指定ALS中的正则化参数。
    |implicitPrefs:指定是使用显式反馈 ALS变体还是使用适用于隐式反馈数据的变量 。
    |α:是适用于ALS的隐式反馈变体的参数,其控制偏好观察中的 基线置信度。
  """.stripMargin
  def main(args: Array[String]): Unit = {
    //屏蔽日志
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    val spark = SparkSession
      .builder()
      .appName(s"${this.getClass.getSimpleName}")
      .master("local[4]")
      .getOrCreate()

    //加载数据
    val data = spark.read.textFile("D:\\nobody\\src\\main\\scala\\mllib\\data\\u.data").distinct()
    val ratings: RDD[Rating] = data.rdd.map(_.split("\t") match {
      case Array(user, item, rate, time) => Rating(user.toInt, item.toInt, rate.toDouble)
    })
    //    ratings.show(false)
    val rank = 10
    val numIterations = 10
    val lambda = 0.01
    val model = ALS.train(ratings, rank, numIterations, lambda)
    """
      |模型评估
    """.stripMargin

    val usersProducts: RDD[(Int, Int)] = ratings.map { case Rating(user, product, rate) =>
      (user, product)
    }
    //预测数据
    val predictions = model.predict(usersProducts).map { case Rating(user, product, rate) =>
      ((user, product), rate)
    }
    //将真实分数与预测分数进行合并
    val ratesAndPreds = ratings.map { case Rating(user, product, rate) =>
      ((user, product), rate)
    }.join(predictions)
    //计算均方差
    val MSE = ratesAndPreds.map { case ((user, product), (r1, r2)) =>
      val err = (r1 - r2)
      err * err
    }.mean()
    println("Mean Squared Error = " + MSE)
    """
      |模型保存及加载
    """.stripMargin
    /*model.save(spark.sparkContext,"D:\\nobody\\src\\main\\scala\\mllib\\data\\model")
    val sameModel = MatrixFactorizationModel.load(spark.sparkContext,"D:\\nobody\\src\\main\\scala\\mllib\\data\\model")*/
  }
}

加载训练好的模型进行推荐

import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.recommendation.{MatrixFactorizationModel, Rating}
import org.apache.spark.sql.SparkSession
import org.jblas.DoubleMatrix
import scala.collection.Map
/**
  * Created by win7 on 2018/10/23.
  *
  * 加载协同过滤模型进行推荐
  */
object loadmodel {
  def main(args: Array[String]): Unit = {
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    val spark = SparkSession
      .builder()
      .appName(s"${this.getClass.getSimpleName}")
      .master("local[4]")
      .getOrCreate()
    val model = MatrixFactorizationModel.load(spark.sparkContext, "D:\\nobody\\src\\main\\scala\\mllib\\data\\model")
    """
      |各种推荐方式
      |1.根据用户推荐物品
      |2.根据用户推荐用户
      |3.根据用户推荐用户
      |4.根据物品推荐物品
    """.stripMargin
    println("-----------------基于用户推荐--------根据用户推荐物品及根据物品推荐用户---------")
    val movies = spark.sparkContext.textFile("D:\\nobody\\src\\main\\scala\\mllib\\data\\u.item")
    //电影id  电影名称
    val titles:Map[Int,String] = movies.map(line => line.split("\\|").take(2)).map(array => (array(0).toInt, array(1))).collectAsMap()
    //给111用户推荐 10部电影
    """
      |为单个用户推荐商品
      |指定 用户和推荐个数
    """.stripMargin
    val userId = 111
    val n = 10
    val topn = model.recommendProducts(userId, n)
    //    println(topn.mkString("\n"))
    """
      |给所有用户推荐商品
      |指定推荐个数即可
    """.stripMargin
    //给所有用户进行推荐
    model.recommendProductsForUsers(10).flatMap(x => {
      val user = x._1.toString
      val rat = x._2
      var res = List[(String, String, String)]()
      for (r <- rat) {
        res = res :+ (user, r.product + ",", titles(r.product) + "," + r.rating)
      }
      res
    })//.foreach(println)
    """
      |给产品推荐用户 两种方式
      |指定商品id 和 推荐用户个数
    """.stripMargin
    model.recommendUsers(451,10)//.foreach(println)
    """
      |给所有产品推荐用户
      |指定推荐个数即可
    """.stripMargin
    model.recommendUsersForProducts(10)
  """
    |根据物品推荐物品
    |
  """.stripMargin
  """
    |根据某物品推荐物品
    |基于物品推荐物品的,可以将推荐结果事先保存到es中,大数据系统直接取检索,即可得到推荐的结果
    |推荐没天进行更新一次
  """.stripMargin
    val ss: String = similarProduct(model,230,10).toList.mkString(":::")
    println(ss)
    """
      |找到所有物品的最类似的物品
      |与本身最相近的还是本身,所以如果取前10个,N需要设置为11
    """.stripMargin
    titles.map(tuple=>{
      val recomList = similarProduct(model,tuple._1,10)
      (tuple._1,recomList.toList.mkString(":::"))
    })//.foreach(println)
  }
  /**
    * 计算余弦相似度
    * @param vec1
    * @param vec2
    * @return
    */
  def cosineSimilarity(vec1: DoubleMatrix, vec2: DoubleMatrix): Double = {
    vec1.dot(vec2) / (vec1.norm2() * vec2.norm2())
  }
  /**
    * 得到用户因子和物品因子
    */
  def obtainFeatures(model: MatrixFactorizationModel) = {
    val userFeatures = model.userFeatures
    val productFeatures = model.productFeatures
    (userFeatures, productFeatures)
  }
  /**
    * 求某个物品与各个物品的余弦相似度
    */
  def productCosineSimilarity(model: MatrixFactorizationModel, itemId: Int) = {
    val itemFactor = model.productFeatures.lookup(itemId).head
    val itemVector = new DoubleMatrix(itemFactor)

    val sims = model.productFeatures.map {
      case (id, factor) => {
        val factorVector = new DoubleMatrix(factor)
        val sim = this.cosineSimilarity(factorVector, itemVector)
        (id, sim)
      }
    }
    sims
  }

 
  /**
    * 求与某个物品相似的前N的物品
    */
  def similarProduct(model: MatrixFactorizationModel, itemId: Int, N: Int = 10) = {
    val sims = this.productCosineSimilarity(model, itemId)
    val sortedSims = sims.top(N)(Ordering.by { x => x._2})

    sortedSims
  }
}

 

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