BPR

    科技2022-07-11  145

    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 scores class BPR: user_count = 10000 item_count = 5000 latent_factors = 10 lr = 0.01 reg = 0.01 train_count = 1000 train_data_path = 'train.txt' test_data_path = 'test.txt' size_u_i = user_count * item_count U = np.random.rand(user_count, latent_factors) * 0.01 V = np.random.rand(item_count, latent_factors) * 0.01 biasV = np.random.rand(item_count) * 0.01 test_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_ratings def 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] = 1 def train(self, user_ratings_train): for user in range(self.user_count): # sample a user u = random.randint(1, self.user_count) if u not in user_ratings_train.keys(): continue # sample a positive item from the observed items i = random.sample(user_ratings_train[u], 1)[0] # sample a negative item from the unobserved items j = random.randint(1, self.item_count) while j in user_ratings_train[u]: j = random.randint(1, self.item_count) u -= 1 i -= 1 j -= 1 r_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_uj loss_func = -1.0 / (1 + np.exp(r_uij)) # update U and V self.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 biasV self.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 predict def 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] = 1 else: self.test[u * self.item_count + item] = 0 # training for i in range(self.train_count): self.train(user_ratings_train) predict_matrix = self.predict(self.U, self.V) # prediction self.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 evaluation scores.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] = 0 return predict if __name__ == '__main__': bpr = BPR() bpr.main()
    Processed: 0.023, SQL: 8