BPB模型概念
BPR(Bayesian Personalized Ranking)推荐模型是基于贝叶斯后验优化的个性化排序算法。从user-iem矩阵训练出多个矩阵,而且一个矩阵表示一个用户的item偏好情况来获得用对多个item的偏好关系的推荐系统。本身不优化用户对物品的评分,只是借由评分来优化用户对物品的排序。
BPR是目前主流的利用基于物品对的协同过滤技术解决OCCF问题的算法之 。
BPR的核心是针对两个物品的相对偏好排序进行建模。最终为每个用户计算其对没有过行为物品的偏好排序,从而进行个性化推荐。
由此,训练集Ds可以构建为:U ∗ I ∗ I ,Ds是三元组( u , i , j )的集合。
BPR模型特点
1、强调个性化推荐,个性化物品偏好排名
2、用后验概率优化个性化推荐的排序
3、基于梯度下降的learnBPR极大化BPR-OPT
4、一般的推荐算法强调用户对项目的打分,只存在用户和单个项目的关系,不去考虑两个项目对用户的影响力,而BPR模型从u , i , j 出发求解u , i ,j的大小。
BPR模型过程
(1)从user-item中提取item-item矩阵
?表示无签到数据,有两种情况,第一种可能本身就是negative value,用户对item不感兴趣,第二种是缺失值,发生了浏览或者购买行为但是丢失了
- 表示用户u相对于item j更喜欢item i。
BPR推荐系统会考虑positive value和negative value,也就是所有item都会被个性化ranking,即使用户对某个item缺失值这个item也能够被ranking,而不是仅仅用negative value代替缺失值。
BPR算法步骤
基本假设
1.每个用户之间的偏好行为相互独立
2.统一用户对不同物品的喜好相互独立
数据pair预处理
BPR算法将用户对物品的评分(显示反馈1,隐式反馈0)处理为一个pair集合<i,j>,其中i为评分为1的物品,j为评分为0 的物品,假设用户有M个1的评分,N个0的评分,则该用户共有M*N个pair对。
数据集就由<u,i,j>表示,相对于物品j,用户u更喜欢物品i。
优化
基于前面提到的两个基本假设,优化问题就转化为了极大化以下目标:
θ为模型参数,包括用户的latent matrix P(表示用户的隐含因子矩阵P)物品的latent matrix Q(表达物品的隐含因子矩阵Q)
基于pair-wise的偏序优化,可以避免point-wise模型在对feature-item进行预测时失效(因为feature-item在训练时全被标记为“0”)的问题。
而且feature-item包括两类:1,用户真正讨厌的;2,用户missing的。
对于某个用户来说,在训练时都被标为"0"的item,在预测时的评分也可以排序,因此不影响ranking任务的完成。
即使用pair-wise的优化方式,可以对训练时标记为“0”的item在预测时进行ranking。
但这本身是“矬子里面拔高个”,且训练数据与用户的实际偏好不符。而且,从数据量考虑,也很不经济。
import random
from collections import defaultdict
import numpy as np
from sklearn.metrics import roc_auc_score
import scoresclass BPR:user_count = 10000item_count = 5000latent_factors = 10lr = 0.01reg = 0.01train_count = 1000train_data_path = 'train.txt'test_data_path = 'test.txt'size_u_i = user_count * item_countU = np.random.rand(user_count, latent_factors) * 0.01V = np.random.rand(item_count, latent_factors) * 0.01biasV = np.random.rand(item_count) * 0.01test_data = np.zeros((user_count, item_count))test = np.zeros(size_u_i)predict_ = np.zeros(size_u_i)def load_data(self, path):user_ratings = defaultdict(set)with open(path, 'r') as f:for line in f.readlines():u, i = line.split(" ")u = int(u)i = int(i)user_ratings[u].add(i)return user_ratingsdef load_test_data(self, path):file = open(path, 'r')for line in file:line = line.split(' ')user = int(line[0])item = int(line[1])self.test_data[user - 1][item - 1] = 1def train(self, user_ratings_train):for user in range(self.user_count):# sample a useru = random.randint(1, self.user_count)if u not in user_ratings_train.keys():continue# sample a positive item from the observed itemsi = random.sample(user_ratings_train[u], 1)[0]# sample a negative item from the unobserved itemsj = random.randint(1, self.item_count)while j in user_ratings_train[u]:j = random.randint(1, self.item_count)u -= 1i -= 1j -= 1r_ui = np.dot(self.U[u], self.V[i].T) + self.biasV[i]r_uj = np.dot(self.U[u], self.V[j].T) + self.biasV[j]r_uij = r_ui - r_ujloss_func = -1.0 / (1 + np.exp(r_uij))# update U and Vself.U[u] += -self.lr * (loss_func * (self.V[i] - self.V[j]) + self.reg * self.U[u])self.V[i] += -self.lr * (loss_func * self.U[u] + self.reg * self.V[i])self.V[j] += -self.lr * (loss_func * (-self.U[u]) + self.reg * self.V[j])# update biasVself.biasV[i] += -self.lr * (loss_func + self.reg * self.biasV[i])self.biasV[j] += -self.lr * (-loss_func + self.reg * self.biasV[j])def predict(self, user, item):predict = np.mat(user) * np.mat(item.T)return predictdef main(self):user_ratings_train = self.load_data(self.train_data_path)self.load_test_data(self.test_data_path)for u in range(self.user_count):for item in range(self.item_count):if int(self.test_data[u][item]) == 1:self.test[u * self.item_count + item] = 1else:self.test[u * self.item_count + item] = 0# trainingfor i in range(self.train_count):self.train(user_ratings_train)predict_matrix = self.predict(self.U, self.V)# predictionself.predict_ = predict_matrix.getA().reshape(-1)self.predict_ = pre_handel(user_ratings_train, self.predict_, self.item_count)auc_score = roc_auc_score(self.test, self.predict_)print('AUC:', auc_score)# Top-K evaluationscores.topK_scores(self.test, self.predict_, 5, self.user_count, self.item_count)def pre_handel(set, predict, item_count):# Ensure the recommendation cannot be positive items in the training set.for u in set.keys():for j in set[u]:predict[(u - 1) * item_count + j - 1] = 0return predictif __name__ == '__main__':bpr = BPR()bpr.main()