zoukankan      html  css  js  c++  java
  • 转推荐算法——基于矩阵分解的推荐算法

    推荐算法概述

    对于推荐系统(Recommend System, RS),从广义上的理解为:为用户(User)推荐相关的商品(Items)。常用的推荐算法主要有:

    • 基于内容的推荐(Content-Based Recommendation)
    • 协同过滤的推荐(Collaborative Filtering Recommendation)
    • 基于关联规则的推荐(Association Rule-Based Recommendation)
    • 基于效用的推荐(Utility-Based Recommendation)
    • 基于知识的推荐(Knowledge-Based Recommendation)
    • 组合推荐(Hybrid Recommendation)

    在推荐系统中,最重要的数据是用户对商品的打分数据,数据形式如下所示:

    这里写图片描述

    其中,U1U5表示的是5个不同的用户,D1D4表示的是4个不同的商品,这样便构成了用户-商品矩阵,在该矩阵中,有用户对每一件商品的打分,其中“-”表示的是用户未对该商品进行打分。

    在推荐系统中有一类问题是对未打分的商品进行评分的预测。

    目前推荐系统中用的最多的就是矩阵分解方法,在Netflix Prize推荐系统大赛中取得突出效果。以用户-项目评分矩阵为例,矩阵分解就是预测出评分矩阵中的缺失值,然后根据预测值以某种方式向用户推荐。常见的矩阵分解方法有基本矩阵分解(basic MF),正则化矩阵分解)(Regularized MF),基于概率的矩阵分解(PMF)等。今天以“用户-项目评分矩阵R(N×M)”说明三种分解方式的原理以及应用。

    用户-项目评分矩阵

    • Basic MF:

      Basic MF是最基础的分解方式,将评分矩阵R分解为用户矩阵U和项目矩阵S, 通过不断的迭代训练使得U和S的乘积越来越接近真实矩阵,矩阵分解过程如图: 
      矩阵分解过程

      预测值接近真实值就是使其差最小,这是我们的目标函数,然后采用梯度下降的方式迭代计算U和S,它们收敛时就是分解出来的矩阵。我们用损失函数来表示误差(等价于目标函数): 
      损失函数 公式1

      公式1中R_ij是评分矩阵中已打分的值,U_i和S_j相当于未知变量。为求得公式1的最小值,相当于求关于U和S二元函数的最小值(极小值或许更贴切)。通常采用梯度下降的方法: 
      梯度下降

      学习速率是学习速率,表示迭代的步长。其值为1.5时,通常以震荡形式接近极值点;若<1迭代单调趋向极值点;若>2围绕极值逐渐发散,不会收敛到极值点。具体取什么值要根据实验经验。


      • Regularized MF

        正则化矩阵分解是Basic MF的优化,解决MF造成的过拟合问题。其不是直接最小化损失函数,而是在损失函数基础上增加规范化因子,将整体作为损失函数。 
        Regularized MF

        红线表示正则化因子,在求解U和S时,仍然采用梯度下降法,此时迭代公式变为:(图片截取自相关论文,S和V等价) 
        梯度下降

        其中, E

        梯度下降结束条件:f(x)的真实值和预测值小于自己设定的阈值(很小的值,之前一直理解为是变量U和V的迭代值差小于阈值就行,弄了一天才懂。)

    程序实现

    对于上述的评分矩阵,通过矩阵分解的方法对其未打分项进行预测,最终的结果为:

    这里写图片描述

    程序代码如下:

    #!/bin/python
    '''
    Date:20160411
    @author: zhaozhiyong
    '''
    from numpy import *
    
    def load_data(path):
        f = open(path)
        data = []
        for line in f.readlines():
            arr = []
            lines = line.strip().split("	")
            for x in lines:
                if x != "-":
                    arr.append(float(x))
                else:
                    arr.append(float(0))
            #print arr
            data.append(arr)
        #print data
        return data
    
    def gradAscent(data, K):
        dataMat = mat(data)
        print dataMat
        m, n = shape(dataMat)
        p = mat(random.random((m, K)))
        q = mat(random.random((K, n)))
    
        alpha = 0.0002
        beta = 0.02
        maxCycles = 10000
    
        for step in xrange(maxCycles):
            for i in xrange(m):
                for j in xrange(n):
                    if dataMat[i,j] > 0:
                        #print dataMat[i,j]
                        error = dataMat[i,j]
                        for k in xrange(K):
                            error = error - p[i,k]*q[k,j]
                        for k in xrange(K):
                            p[i,k] = p[i,k] + alpha * (2 * error * q[k,j] - beta * p[i,k])
                            q[k,j] = q[k,j] + alpha * (2 * error * p[i,k] - beta * q[k,j])
    
            loss = 0.0
            for i in xrange(m):
                for j in xrange(n):
                    if dataMat[i,j] > 0:
                        error = 0.0
                        for k in xrange(K):
                            error = error + p[i,k]*q[k,j]
                        loss = (dataMat[i,j] - error) * (dataMat[i,j] - error)
                        for k in xrange(K):
                            loss = loss + beta * (p[i,k] * p[i,k] + q[k,j] * q[k,j]) / 2
    
            if loss < 0.001:
                break
            #print step
            if step % 1000 == 0:
                print loss
    
        return p, q
    
    
    if __name__ == "__main__":
        dataMatrix = load_data("./data")
    
        p, q = gradAscent(dataMatrix, 5)
        '''
        p = mat(ones((4,10)))
        print p
        q = mat(ones((10,5)))
        '''
        result = p * q
        #print p
        #print q
    
        print result

    其中,利用梯度下降法进行矩阵分解的过程中的收敛曲线如下所示:

    这里写图片描述

    '''
    Date:20160411
    原文作者:@author: zhaozhiyong
    '''
    
    from pylab import *
    from numpy import *
    
    data = []
    
    f = open("result")
    for line in f.readlines():
        lines = line.strip()
        data.append(lines)
    
    n = len(data)
    x = range(n)
    plot(x, data, color='r',linewidth=3)
    plt.title('Convergence curve')
    plt.xlabel('generation')
    plt.ylabel('loss')
    show()
  • 相关阅读:
    Two Sum II
    Subarray Sum
    Intersection of Two Arrays
    Reorder List
    Convert Sorted List to Binary Search Tree
    Remove Duplicates from Sorted List II
    Partition List
    Linked List Cycle II
    Sort List
    struts2结果跳转和参数获取
  • 原文地址:https://www.cnblogs.com/onemorepoint/p/8167942.html
Copyright © 2011-2022 走看看