美文网首页
构建基于Spark的推荐系统

构建基于Spark的推荐系统

作者: Haraway | 来源:发表于2017-12-12 10:36 被阅读0次

    一、推荐模型的分类

    1,基于内容的过滤

      利用物品的内容或是属性信息以及某些相似度定义,来求出与该物品类似的物品。

    2,协同过滤

      利用大量已有用户偏好来估计用户对其未接触过的物品的喜好程度。

    3,矩阵分解

    a,显式矩阵分解

      当要处理的数据是由用户所提供的自身的偏好数据,这些数据被称为显式偏好数据。这些数据包括如物品评级、赞、喜欢等用户对物品的评价。

    b,隐式矩阵分解

      用户对物品的偏好不会直接给出,而是隐含在用户与物品的交互之中。二元数据(比如用户是否观看了某个电影或是是否购买了某个商品)和技术数据(比如用户观看某电影的次数)便是这类数据。

    c,最小二乘法

      最小二乘法(Altermating Least Squares,ALS)是一种求解矩阵分解的最优化方法。
      ALS的实现原理是迭代求解一系列最小二乘回归问题。在每次迭代时,固定用用户因子矩阵或是物品因子矩阵中的一个,然后用固定的这个矩阵以及评级数据来更新另一个矩阵。之后,被更新的矩阵被固定住,再更新另外一个矩阵。如此迭代,直到模型收敛(或是迭代了预设计好的次数)。

    二、提取有效特征

    我们采用显式评级数据,而不是使用其他用户或物品的元数据以及“用户-物品”交互数据。

    MacBook-Pro:bin xp$ spark-shell
    Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
    Setting default log level to "WARN".
    To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
    17/12/11 17:28:24 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
    17/12/11 17:28:29 WARN ObjectStore: Failed to get database global_temp, returning NoSuchObjectException
    Spark context Web UI available at http://172.16.253.3:4040
    Spark context available as 'sc' (master = local[*], app id = local-1512984505032).
    Spark session available as 'spark'.
    Welcome to
          ____              __
         / __/__  ___ _____/ /__
        _\ \/ _ \/ _ `/ __/  '_/
       /___/ .__/\_,_/_/ /_/\_\   version 2.2.0
          /_/
             
    Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131)
    Type in expressions to have them evaluated.
    Type :help for more information.
    

    先查看原始信息,该数据由用户ID、影片ID、星级和时间戳等字段依次组成,各字段间用制表符分隔。

    scala> val rawData=sc.textFile("/Users/xp/mlpy/ml-100k/u.data")
    

    输出如下:

    rawData: org.apache.spark.rdd.RDD[String] = /Users/xp/mlpy/ml-100k/u.data MapPartitionsRDD[1] at textFile at <console>:24

    scala> rawData.first()
    

    输出如下:

    res0: String = 196 242 3 881250949

    由于时间戳是不需要的,那我们简单的提取前3个字段即可:

    scala> val rawRatings=rawData.map(_.split("\t").take(3))
    

    rawRatings: org.apache.spark.rdd.RDD[Array[String]] = MapPartitionsRDD[2] at map at <console>:26

    上面先对各个记录用\t分割,这会返回一个Array[String]数组。之后调用Scala的take函数来仅保留数组的前三个元素,分别对应用户ID、影片ID、星级。
    rawRatings.first()命令只会将新RDD的第一条记录返回到驱动程序。通过调用它,我们可以检查一下新RDD。

    scala> rawRatings.first()
    

    res1: Array[String] = Array(196, 242, 3)

    scala> import org.apache.spark.mllib.recommendation.ALS
    

    import org.apache.spark.mllib.recommendation.ALS

    scala> ALS.train
    

    <console>:25: error: ambiguous reference to overloaded definition,
    both method train in object ALS of type (ratings: org.apache.spark.rdd.RDD[org.apache.spark.mllib.recommendation.Rating], rank: Int, iterations: Int)org.apache.spark.mllib.recommendation.MatrixFactorizationModel
    and method train in object ALS of type (ratings: org.apache.spark.rdd.RDD[org.apache.spark.mllib.recommendation.Rating], rank: Int, iterations: Int, lambda: Double)org.apache.spark.mllib.recommendation.MatrixFactorizationModel
    match expected type ?
    ALS.train
    ^

    这个错误提示,所需提供的输入参数至少有ratings、rank和iterations。第二个函数另外还需要一个lambda参数。导入上面提到的Rating类,再类似的输入Rating()后回车,便可看到Rating对象所需的参数:

    scala> import org.apache.spark.mllib.recommendation.Rating
    

    import org.apache.spark.mllib.recommendation.Rating

    scala> Rating()
    

    <console>:26: error: not enough arguments for method apply: (user: Int, product: Int, rating: Double)org.apache.spark.mllib.recommendation.Rating in object Rating.
    Unspecified value parameters user, product, rating.
    Rating()
    ^

    上述输出表明ALS模型需要一个由Rating记录构成的RDD,而Rating类则是对用户ID、影片ID(这里是通称product)和实际星级这些参数封装。我们可以 调用map方法将原来的各ID和星级的数组转换为对应的Rating对象,从而创建所需的评级数据集。

    scala> val ratings=rawRatings.map{case Array(user,movie,rating) => Rating(user.toInt,movie.toInt,rating.toDouble)}
    

    ratings: org.apache.spark.rdd.RDD[org.apache.spark.mllib.recommendation.Rating] = MapPartitionsRDD[3] at map at <console>:30

    scala> ratings.first()
    

    res5: org.apache.spark.mllib.recommendation.Rating = Rating(196,242,3.0)

    三、训练推荐模型

      从原始数据提取出这些简单特征后,便可训练模型。
    训练模型所需的其他参数有以下几个:
    rank:对应ALS模型中的因子个数。其合理值为10-200.
    iterations:对应运行时的迭代次数。合理值10次左右。
    lambda:该参数控制模型的正则化过程,从而控制模型的过拟合情况。

    scala> val model=ALS.train(ratings,50,10,0.01)
    

    17/12/11 17:36:04 WARN BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS
    17/12/11 17:36:04 WARN BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeRefBLAS
    17/12/11 17:36:04 WARN LAPACK: Failed to load implementation from: com.github.fommil.netlib.NativeSystemLAPACK
    17/12/11 17:36:04 WARN LAPACK: Failed to load implementation from: com.github.fommil.netlib.NativeRefLAPACK
    model: org.apache.spark.mllib.recommendation.MatrixFactorizationModel = org.apache.spark.mllib.recommendation.MatrixFactorizationModel@27ee8493

    scala> model.userFeatures
    

    res6: org.apache.spark.rdd.RDD[(Int, Array[Double])] = users MapPartitionsRDD[209] at mapValues at ALS.scala:271

    scala> model.userFeatures.count
    

    res7: Long = 943

    scala> model.productFeatures.count
    

    res8: Long = 1682

    四、使用推荐模型

      用户推荐具体的实现方法取决于所采用的模型。比如若采用基于用户的模型,则会利用相似用户的评级来计算某个用户的推荐。而若采用基于物品的模型,则会依靠用户接触过的物品与候选物品之间的相似度来获得推荐。

      利用矩阵分解方法时,是直接对评级数据进行建模,所以预计得分可视作相应用户因子向量和物品向量的点积。

    scala> val predictedRating=model.predict(789,123)
    

    predictedRating: Double = 3.5709657849060057

    可以看到,该模型预测用户789对电影123的评级3.57。

    scala> val userId=789
    

    userId: Int = 789

    scala> val K=10
    

    K: Int = 10

    scala> val topKRecs=model.recommendProducts(userId,K)
    

    topKRecs: Array[org.apache.spark.mllib.recommendation.Rating] = Array(Rating(789,156,5.575635336185863), Rating(789,42,5.529139597902855), Rating(789,179,5.516092734457448), Rating(789,39,5.400058460147818), Rating(789,180,5.3832945184540755), Rating(789,195,5.3781917200594105), Rating(789,671,5.375058224290015), Rating(789,663,5.2987123201627355), Rating(789,92,5.278211419850456), Rating(789,647,5.165706252282592))

    scala> println(topKRecs.mkString("\n"))
    

    Rating(789,156,5.575635336185863)
    Rating(789,42,5.529139597902855)
    Rating(789,179,5.516092734457448)
    Rating(789,39,5.400058460147818)
    Rating(789,180,5.3832945184540755)
    Rating(789,195,5.3781917200594105)
    Rating(789,671,5.375058224290015)
    Rating(789,663,5.2987123201627355)
    Rating(789,92,5.278211419850456)
    Rating(789,647,5.165706252282592)

    这就求得了为用户789所能推荐的物品以及对应的预计得分。

    详细案例查看:《Spark机器学习》第4章

    参考:
    1,用户兴趣模型分类以及推荐系统技术调研

    2,主流推荐算法的分类及介绍

    相关文章

      网友评论

          本文标题:构建基于Spark的推荐系统

          本文链接:https://www.haomeiwen.com/subject/uzfwixtx.html