【推荐算法】从零开始做推荐(三)——传统矩阵分解的TopK推荐实战

前言

  在前两章,我们已对本系列的数据集、评价指标做了相应的介绍,从本章开始将进行推荐实战,算法上从最经典的矩阵分解讲起。

  如果你对本系列(未写完,持续更新中)感兴趣,可接以下传送门:
  【推荐算法】从零开始做推荐(一)——认识推荐、认识数据
  【推荐算法】从零开始做推荐(二)——推荐系统的评价指标,计算原理与实现样例
  【推荐算法】从零开始做推荐(三)——传统矩阵分解的TopK推荐
  【推荐算法】从零开始做推荐(四)——python Keras框架 利用Embedding实现矩阵分解TopK推荐
  【推荐算法】从零开始做推荐(五)——贝叶斯个性化排序矩阵分解 (BPRMF) 推荐实战
  【推荐算法】从零开始做推荐(六)——贝叶斯性化排序矩阵分解 (BPRMF) 的Tensorflow版

矩阵分解

  本系列以实战为主,算法上讲下大概的思想。矩阵分解较全的分析介绍可参照机器学习矩阵分解解析Recommender.Matrix.Factorization。本文实现的是最简的矩阵分解版本,详细思想参照矩阵分解在协同过滤推荐算法中的应用,主体算法公式参照梯度下降的矩阵分解公式推导
  什么是矩阵分解?
  下面进行简单介绍。矩阵分解,顾名思义是将矩阵进行拆分,线性代数里两个矩阵相乘可以得到一个新的矩阵,而矩阵分解的思想就是矩阵乘法的逆运用,将一个矩阵分解成两个矩阵相乘。注意,这里的分解是近似的,因为有可能找不出两个矩阵的乘积恰好等于原矩阵。而这个近似就给推荐带来了思路。
  分解前的矩阵是什么?
  答:用户与项目的交互矩阵,具体含义可以是评分、签到、点击等等。大致分为两类,一类是0-1矩阵,即有过交互即为1,否则为0;另一类是具体的数值,根据交互的次数、评价等得出。这里我们用Rating代指分解前的矩阵。
  分解后的两个矩阵分别是什么?
  答:分别为用户隐因子矩阵、项目隐因子矩阵,中间维度K认为是特征的数量。这样一来就用两个矩阵分别表示了用户与项目。假设Rating的维度是M×N的,那么就可以分解为M×K的User矩阵,K×N的Item矩阵,满足矩阵Rating和矩阵[User×Item]中的非零项尽可能相等。
在这里插入图片描述
  为什么要矩阵分解?
  答:无论Rating是何种矩阵,我们都默认了如果用户和项目未交互则对应位置填0,但实际上用户对该项目是可能感兴趣的,如何得到这个兴趣程度呢?我们让分解后的矩阵尽量与原矩阵逼近,注意,逼近的只有原矩阵的非零项。因为是近似的分解,所以得到的新矩阵,原先非零位置就有了数值,于是我们就可以根据新矩阵的数值由大到小进行排序取前K个进行TopK推荐。

核心算法

  自己写是不可能自己写的,Github上虽然有很多,但都是面向对象的写法。面向对象的代码尽管复用性强,也易于修改,但就是写得太罗嗦,不能很直观的理解。
  这里与理论统一,对网上一个广泛流传的版本进行修改,先看理论部分:
在这里插入图片描述
  修改完的代码如下,采用的是最简单版本的梯度下降,步长alpha和正则lamda(正确打法是lambda,代码写lamda是为了与python中的关键字作区分)固定。
  对梯度下降感兴趣的可以重点看下这段代码,关键之处在于梯度下降结束的三个条件:
  梯度下降结束条件:
    1.满足最大迭代次数;
    2.loss过小;
    3.loss之差过小,梯度消失。

# -*- coding: utf-8 -*-
"""
Created on Fri Apr 10 14:42:17 2020

@author: Yang Lechuan
"""
import numpy as np
import time 
def matrix_factorization(R,P,Q,d,steps,alpha=0.05,lamda=0.002):
    Q=Q.T
    sum_st = 0 #总时长
    e_old = 0 #上一次的loss
    flag = 1
    for step in range(steps): #梯度下降结束条件:1.满足最大迭代次数,跳出
        st = time.time()
        e_new = 0
        for u in range(len(R)):
            for i in range(len(R[u])):
                if R[u][i]>0:
                    eui=R[u][i]-np.dot(P[u,:],Q[:,i])
                    for k in range(d):
                        P[u][k] = P[u][k] + alpha*eui * Q[k][i]- lamda *P[u][k]
                        Q[k][i] = Q[k][i] + alpha*eui * P[u][k]- lamda *Q[k][i]
        cnt = 0
        for u in range(len(R)):
            for i in range(len(R[u])):
                if R[u][i]>0:
                    cnt = cnt + 1
                    e_new = e_new + pow(R[u][i]-np.dot(P[u,:],Q[:,i]),2)
        et = time.time()
        e_new = e_new / cnt
        if step == 0: #第一次不算loss之差
            e_old = e_new
            continue
        sum_st = sum_st + (et-st)
        if e_new<1e-3:#梯度下降结束条件:2.loss过小,跳出
            flag = 2
            break
        if e_old - e_new<1e-10:#梯度下降结束条件:3.loss之差过小,梯度消失,跳出
            flag = 3
            break
        else:
            e_old = e_new
    print('---------Summary----------\n',
      'Type of jump out:',flag,'\n',
      'Total steps:',step + 1,'\n',
      'Total time:',sum_st,'\n',
      'Average time:',sum_st/(step+1.0),'\n',
      "The e is:",e_new)        
    return P,Q.T

R=[
   [5,2,0,3,1],
   [0,2,1,4,5],
   [1,1,0,2,4],
   [2,2,0,5,0]
   ]
d = 3
steps = 5000
N = len(R)
M = len(R[0])
P = np.random.normal(loc=0,scale=0.01,size=(N,d)) #正态分布随机初始化
Q = np.random.normal(loc=0,scale=0.01,size=(M,d))
nP,nQ = matrix_factorization(R,P,Q,d,steps)
print('-----原矩阵R:------')
print(R)
print('-----近似矩阵nR:------')
print(np.dot(nP,nQ.T))

  这块代码的目的是为了验证,我们的矩阵分解算法是否真的做到了分解。来看看结果。
在这里插入图片描述
  简单来讲,行就是用户,列就是项目,数值可看成评分。可以看出,原先为0的位置也有了评分,我们依靠新矩阵的评分进行推荐。
  注意,这里的e是指损失函数,用的是MSE,计算公式如下:
在这里插入图片描述

ML100K实现完整的矩阵分解TopK推荐

  数据集介绍及训练集测试集划分请看【推荐算法】从零开始做推荐(一)——认识推荐、认识数据
评价指标请看【推荐算法】从零开始做推荐(二)——推荐系统的评价指标,计算原理与实现样例
  简单的数据集介绍:
在这里插入图片描述

构造矩阵

  要将矩阵分解的核心算法进行应用到数据集上,首先要根据数据集得到矩阵R,数据集直接由评分这列,非常简单就可以实现。

def getUI(dsname,dformat): #获取全部用户和项目
    st = time.time()
    train = pd.read_csv(dsname+'_train.txt',header = None,names = dformat
  • 11
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lechuan_dafo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值