BPR

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矩阵
BPR_第1张图片
?表示无签到数据,有两种情况,第一种可能本身就是negative value,用户对item不感兴趣,第二种是缺失值,发生了浏览或者购买行为但是丢失了

  • 表示用户u相对于item j更喜欢item i。
    BPR推荐系统会考虑positive value和negative value,也就是所有item都会被个性化ranking,即使用户对某个item缺失值这个item也能够被ranking,而不是仅仅用negative value代替缺失值。
    BPR_第2张图片
    BPR算法步骤
    基本假设
    1.每个用户之间的偏好行为相互独立
    2.统一用户对不同物品的喜好相互独立
    数据pair预处理
    BPR算法将用户对物品的评分(显示反馈1,隐式反馈0)处理为一个pair集合,其中i为评分为1的物品,j为评分为0 的物品,假设用户有M个1的评分,N个0的评分,则该用户共有M*N个pair对。
    数据集就由表示,相对于物品j,用户u更喜欢物品i。
    优化
    基于前面提到的两个基本假设,优化问题就转化为了极大化以下目标:
    BPR_第3张图片
    θ为模型参数,包括用户的latent matrix P(表示用户的隐含因子矩阵P)物品的latent matrix Q(表达物品的隐含因子矩阵Q)
    BPR_第4张图片
    基于pair-wise的偏序优化,可以避免point-wise模型在对feature-item进行预测时失效(因为feature-item在训练时全被标记为“0”)的问题。

而且feature-item包括两类:1,用户真正讨厌的;2,用户missing的。

对于某个用户来说,在训练时都被标为"0"的item,在预测时的评分也可以排序,因此不影响ranking任务的完成。

即使用pair-wise的优化方式,可以对训练时标记为“0”的item在预测时进行ranking。

但这本身是“矬子里面拔高个”,且训练数据与用户的实际偏好不符。而且,从数据量考虑,也很不经济。
BPR_第5张图片

BPR_第6张图片

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()

你可能感兴趣的:(BPR)