Fork me on GitHub

BiasLFM分解

  LFM预测是通过隐类将useritem联系起来。但在实际情况下,不同用户的评分标准不同,有的偏高,有的偏低。有的系统有些固有属性和user属性以及item属性都无关。因此才有了带偏置信息的biasLFM

1.预测评分公式为

 

 该式有四项:全局平均分、user的偏置信息、item的偏置信息以及useritem通过隐因子的偏好。

2.损失函数为平方误差+L2正则项,其中是真实评分。

 3.利用SGD训练更新,其中

  •  
  •  
  •  
  •  

 4.程序,完整程序(data from movielens 100k),https://github.com/jiangnanboy/recommendation_methods/blob/master/com/sy/reco/recommendation/matrix_factorization/biaslfm.py

import numpy as np
import math

'''
BiasLFM(bias latent factor model)带偏置项的隐语义推荐模型,加入三个偏置项(所有评分的平均u,用户偏置项bu表示用户的评分习惯和物品没关系,
物品偏置项bi表示物品接受的评分中和用户没关系的因素)矩阵分解,训练得到U,I矩阵,以及用户偏置项和物品偏置项
对user-item评分矩阵进行分解为U、I矩阵,再利用随机梯度下降(函数值下降最快的方向)迭代求解出U,I矩阵以及bu和bi,最后用U*I预测得出user对item的预测评分
这里U矩阵是user对每个隐因子的偏好程度,I矩阵是item在每个隐因子中的分布
'''
class BiasLFM():
    '''
    初始化ratingMatrix,F, alpha, λ
    ratingMatrix:评分矩阵
    F:隐因子数目
    alpha:学习速率
    λ:正则化参数,以防过拟合
    '''
    def __init__(self, ratingMatrix, F, alpha, λ):
        self.ratingMatrix = ratingMatrix
        self.F = F
        self.alpha = alpha
        self.λ = λ

    #对U,I矩阵初始化i,随机填充,根据经验随机数与1/sqrt(F)成正比,bu向量与bi向量初始化为全0,u是所有有评分的全局平均
    def __initPQ(self,userSum,itemSum):
        self.U=np.zeros((userSum,self.F))
        self.I=np.zeros((itemSum,self.F))
        self.bu=np.zeros(userSum)
        self.bi=np.zeros(itemSum)
        self.u=np.mean(self.ratingMatrix[self.ratingMatrix>0])#全局均值
        for i in range(userSum):
            self.U[i]=[np.random.random()/math.sqrt(self.F) for x in range(self.F)]
        for i in range(itemSum):
            self.I[i]=[np.random.random()/math.sqrt(self.F) for x in range(self.F)]

    #预测打分,用户的行与项目的列
    def predict(self,user,item):
        I_T=self.I.T#项目矩阵转置
        pui=self.u+self.bu[user]+self.bi[item]
        pui+=np.dot(self.U[user,:],I_T[:,item])
        return pui

    # 迭代训练分解,max_iter:迭代次数
    def iteration_train(self, max_iter):
        userSum=len(self.ratingMatrix)#用户个数
        itemSum=len(self.ratingMatrix[0])#项目个数
        self.__initPQ(userSum,itemSum)#初始化U,I,bu,bi
        for step in range(max_iter):
            for user in range(userSum):
                for item in range(itemSum):
                    if self.ratingMatrix[user, item] > 0:  # 未评分的项目不参与计算
                        eui=self.ratingMatrix[user,item]-self.predict(user,item)#真实值减去预测的值
                        self.bu[user]+=self.alpha*(eui-self.λ*self.bu[user])#更新bu
                        self.bi[item]+=self.alpha*(eui-self.λ*self.bi[item])#更新bi
                        for f in range(self.F):
                            self.U[user,f]+=self.alpha*(self.I[item,f]*eui-self.λ*self.U[user,f])#更新U
                            self.I[item,f]+=self.alpha*(self.U[user,f]*eui-self.λ*self.I[item,f])#更新I

        predictRating=[]
        for user in range(userSum):
            userItemRating=[]
            for item in range(itemSum):
                pui=self.predict(user,item)
                userItemRating.append(pui)
            predictRating.append(userItemRating)
        return np.round(np.array(predictRating),0)

    # 预测误差训练,convergence:误差收敛,小于这个误差,则终止训练
    def convergence_train(self, convergence):
        userSum = len(self.ratingMatrix)  # 用户个数
        itemSum = len(self.ratingMatrix[0])  # 项目个数
        self.__initPQ(userSum, itemSum)  # 初始化U,I,bu,bi
        flag = True
        while flag:
            for user in range(userSum):
                for item in range(itemSum):
                    if self.ratingMatrix[user, item] > 0:  # 未评分的项目不参与计算
                        eui = self.ratingMatrix[user, item] - self.predict(user, item)  # 真实值减去预测的值
                        self.bu[user] += self.alpha * (eui - self.λ * self.bu[user])  # 更新bu
                        self.bi[item] += self.alpha * (eui - self.λ * self.bi[item])  # 更新bi
                        for f in range(self.F):
                            self.U[user, f] += self.alpha * (self.I[item, f] * eui - self.λ * self.U[user, f])  # 更新U
                            self.I[item, f] += self.alpha * (self.U[user, f] * eui - self.λ * self.I[item, f])  # 更新I

            cost = 0  # 训练误差
            for user in range(userSum):
                for item in range(itemSum):
                    if self.ratingMatrix[user, item] > 0:
                        cost += (1/2)*math.pow(self.ratingMatrix[user, item] - self.predict(user,item), 2)
                        cost+=(1/2)*self.λ*(math.pow(self.bu[user],2)+math.pow(self.bi[item],2))
                        for f in range(self.F):
                            cost += (1 / 2) * self.λ * (math.pow(self.U[user, f], 2) + math.pow(self.I[item, f], 2))
            if cost < convergence:
                flag = False

        predictRating = []
        for user in range(userSum):
            userItemRating = []
            for item in range(itemSum):
                pui = self.predict(user, item)
                userItemRating.append(pui)
            predictRating.append(userItemRating)
        return np.round(np.array(predictRating), 0)

 

posted @ 2020-03-15 15:55  石头木  阅读(377)  评论(0编辑  收藏  举报