• 【机器学习笔记一】协同过滤算法


    参考资料

    【1】《Spark MLlib 机器学习实践》

    【2】http://blog.csdn.net/u011239443/article/details/51752904

    【3】线性代数-同济大学

    【4】基于矩阵分解的协同过滤算法 https://wenku.baidu.com/view/617482a8f8c75fbfc77db2aa.html

    【5】机器学习的正则化 http://www.cnblogs.com/jianxinzhou/p/4083921.html

    【6】正则化方法  http://blog.csdn.net/u012162613/article/details/44261657

    1、协同过滤算法概念

    协同过滤算法是一种基于群体用户或者物品的典型的推荐算法。考虑的推荐思路基于两类:

      1)、基于用户的推荐:认为类似的用户应具备类似的爱好

      2)、基于物品的推荐:认为用户会选择比较接近的物品

    两类思路也存在相应的局限性:

      1)、基于用户的推荐,无法准确找到物品热点,因此经常只反馈常用物品;

      2)、基于物品的推荐,会导致返回相似物品,但用户往往不会购买已经选择过的类似商品;

    2、相似度计算

    假设存在用户和物品的评价矩阵如下:

    1)、基于欧几里得距离的相似度计算

    ,以此公式可知用户1和用户2的相似度为:

    2)、基于余弦角度的相似度计算

    ,以此公式可知用户1和用户2的相似度为:

    备注:2)相当于把欧几里得中的坐标点转换为向量,求向量的夹角

    3、ALS(交替最小二乘法)的一些数学知识备注

    1)可逆矩阵

    对于矩阵,有矩阵,有

    备注:已知对矩阵A实施一次初等行变换,相当于在矩阵的坐标乘以一个矩阵;对矩阵A实施一次初等列变换相当于在矩阵的右边乘以一个矩阵。

    2)特征值

    有矩阵,可计算该矩阵存在特征值3和5,分别对应特征向量

    特征值的几何意义在于该矩阵B乘以一个向量,相当于将这个向量在特征向量方向上做了一个特征值的拉升,其他都是旋转操作。

    在上面的例子中,若给出向量(1,1)则被B左乘后拉升到了(3,3)。由于5这个特征值,特征向量是0,因此无法给出拉升的效果。

    3)特征分解

    对于可对角矩阵可以将矩阵分解称特征值和特征向量的乘积。即,其中

    4)奇异值分解

    对于大部分矩阵来说,特别是非方阵,无法进行特征分解,此时我们采用奇异值分解的方法。

    ,同时用前r大的奇异值来近似描述矩阵,因为奇异值递减的非常快,通常前1%~10%奇异值能够占到全部奇异值之和的99%,这也是协同过滤算法的数据基础。

    4、ALS(交替最小二乘法)算法流程

    在实际协同过滤算法中,并没有直接用奇异值分解,而是用ALS算法直接用低秩矩阵来逼近。

    当采用X来逼近矩阵R时,有Frobenius损失函数:,并增加正则化项

    算法流程如下:

    1、先固定矩阵U为全零

    2、对L(U,V)求V的偏导,使其偏导数全为0,,得出所有的v向量

    3、固定v向量,转而求u,同样使偏导数全为0,有公式,得到所有的u向量

    4、重复步骤2,3,直到损失函数达到目标值。

    4、ALS(交替最小二乘法)在Spark上的例子

    package com.fredric.spark.als;
    
    import org.apache.spark.mllib.recommendation.{Rating, ALS}
    import org.apache.spark.{SparkContext, SparkConf}
    
    /*-
     * 协同过滤算法(ALS)
     * 针对笔记《Spark-协同过滤算法-ALS》
     * Fredric 2017
     */
    object als {
      def main(args:Array[String]): Unit ={
        val conf = new SparkConf().setMaster("local").setAppName("als")
        val sc   = new SparkContext(conf)
    
        val Array = new Array[Rating](5)
    
        //new Rating(user: Int, product: Int, rating: Double)
        Array(0) = new Rating(1,1,0.4)
        Array(1) = new Rating(1,4,0.5)
        Array(2) = new Rating(2,2,0.7)
        Array(3) = new Rating(2,3,0.8)
        Array(4) = new Rating(3,1,0.9)
        Array(4) = new Rating(3,3,0.9)
    
        val data = sc.makeRDD(Array)
    
        val rank          = 2  //隐语义因子的个数。
        val numIterations = 5
        val lambda        = 0.01  //是ALS的正则化参数。
        val model         = ALS.train(data, rank, numIterations, lambda)
    
        //为用户1推荐4款产品
        val rs    = model.recommendProducts(1, 4)
    
        /*
            输入如下:由于用户1与用户3共同爱好了产品1,因此用户3偏好的产品3也被推荐
            Rating(1,4,0.4814649456978035)
            Rating(1,3,0.3956308705617122)
            Rating(1,1,0.38517196440752066)
            Rating(1,2,0.21108557718205034)*/
        rs.foreach(println)
    
      }
    }
  • 相关阅读:
    SQL注入方法之:获取列名
    手把手教会你模拟退火算法
    我的G++编译选项
    编译器优化误解程序员的意思
    ZKW线段树
    扩展欧几里得算法
    快速幂
    乘法取模
    莫队算法良心讲解
    高精度模板
  • 原文地址:https://www.cnblogs.com/Fredric-2013/p/8495896.html
Copyright © 2020-2023  润新知