基于邻域的评分预测

原理:

基于邻域的协同过滤算法主要分为基于用户的协同过滤和基于项目的协同过滤。
基于用户的协同过滤的基本原理是找到与目标用户兴趣相似的其他用户,然后根据这些相似用户的评分来预测目标用户对未评分的项目的评分。具体步骤如下:

  1. 计算用户之间的相似度。这通常可以通过余弦相似度或皮尔逊相关系数来完成,比较两个用户评分的项目,并根据评分是否相似来计算相似度。
  2. 找到与目标用户最相似的K个用户。这可以通过查找相似度最高的K个用户来完成。
  3. 根据这些相似用户的评分来预测目标用户对未评分的项目的评分。这通常采用加权平均的方法,即根据相似度的大小给不同的用户分配不同的权重。
  4. 将预测评分与实际评分进行比较,以评估算法的准确性。这可以通过计算均方根误差(RMSE)、平均绝对误差(MAE)或准确率(Precision)等指标来完成。
    基于项目的协同过滤的基本原理是找到与目标项目相似的一系列项目,然后根据这些相似项目的评分来预测目标项目被未评分用户所评分的概率。具体步骤如下:
  5. 计算项目之间的相似度。这通常可以通过余弦相似度或皮尔逊相关系数来完成,比较两个项目所包含的元素(如关键词、主题等)的相似性。
  6. 找到与目标项目最相似的K个项目。这可以通过查找相似度最高的K个项目来完成。
  7. 根据这些相似项目的评分来预测目标项目被未评分用户所评分的概率。这通常采用加权平均的方法,即根据相似度的大小给不同的项目分配不同的权重。
  8. 将预测评分与实际评分进行比较,以评估算法的准确性。这可以通过计算均方根误差(RMSE)、平均绝对误差(MAE)或准确率(Precision)等指标来完成。

基于项目的协同过滤

import argparse
import random
import pandas as pd
import numpy as np
import math

from operator import itemgetter
from utils import evaluate
from utils import modelType
np.random.seed(1024)


class itemCF():
    # 参数:
    # K:近邻数目
    # test_data:测试数据,二维字典。user->item->评分
    # train_data:训练数据
    # n_users:用户数目
    # n_items:项目数目
    # average_rating:每个项目的平均评分、字典。项目->平均评分
    # item_sim:项目之间的相似度。二维字典。i->j->相似度
    # similarityMeasure:相似度度量,cosine或pearson
    def __init__(self, data_file, K=20,similarityMeasure="cosine"):
        self.K = K  # 近邻数
        self.similarityMeasure=similarityMeasure
        self.loadData(data_file)  # 读取数据
        self.initModel()  # 初始化模型

    def initModel(self):
        # 计算每个物品被用户评分的个数
        item_cnt = {}
        for user, items in self.train_data.items():
            for i in items:
                # count item popularity
                item_cnt.setdefault(i, 0)
                item_cnt[i] += 1

        # 计算每个项目的平均评分
        self.average_rating = {}
        for user, items in self.train_data.items():
            for i in items:
                self.average_rating.setdefault(i, 0)
                self.average_rating[i] += self.train_data[user][i] / item_cnt[i]

        # 计算用户的平均评分
        self.user_average_rating={}
        for user, items in self.train_data.items():
            self.user_average_rating.setdefault(user, 0)
            for i in items:
                self.user_average_rating[user] += self.train_data[user][i] / len(self.train_data[user])

        # 相似度的分子部分
        C2 = dict()
        C3 = dict()
        C1 = dict()
        for user, items in self.train_data.items():
            for i in items:
                for j in items:
                    if i == j:
                        continue
                    C1.setdefault(i, {})
                    C1[i].setdefault(j, 0)
                    C2.setdefault(i, {})
                    C2[i].setdefault(j, 0)
                    C3.setdefault(i, {})
                    C3[i].setdefault(j, 0)

                    if self.similarityMeasure=="cosine":
                        C1[i][j] += ((self.train_data[user][i] - self.user_average_rating[user]) * (
                                self.train_data[user][j] - self.user_average_rating[user]))
                        C2[i][j] += ((self.train_data[user][i] - self.user_average_rating[user]) * (
                                self.train_data[user][i] - self.user_average_rating[user]))
                        C3[i][j] += ((self.train_data[user][j] - self.user_average_rating[user]) * (
                                self.train_data[user][j] - self.user_average_rating[user]))
                    else:
                        C1[i][j] += ((self.train_data[user][i] - self.average_rating[i]) * (
                                self.train_data[user][j] - self.average_rating[j]))
                        C2[i][j] += ((self.train_data[user][i] - self.average_rating[i]) * (
                                self.train_data[user][i] - self.average_rating[i]))
                        C3[i][j] += ((self.train_data[user][j] - self.average_rating[j]) * (
                                self.train_data[user][j] - self.average_rating[j]))

        # 计算最终的物品相似度矩阵
        self.item_sim = dict()
        for i, related_items in C1.items():
            self.item_sim[i] = {}
            for j, cuv in related_items.items():
                if C1[i][j] == 0:
                    self.item_sim[i][j] = 0
                else:
                    self.item_sim[i][j] = C1[i][j] / math.sqrt(C2[i][j] * C3[i][j])

        #每个物品的邻域
        self.item_nei={}
        for item in self.item_sim.keys():
            simi_items=sorted(self.item_sim[item].items(), key=itemgetter(1), reverse=True)[:self.K]
            self.item_nei[item]=simi_items

    def loadData(self, data_file):
        data_fields = ['user_id', 'item_id', 'rating', 'timestamp']
        data = pd.read_table(data_file, names=data_fields)

        self.test_data = {}
        self.train_data = {}

        # 按照1:9划分数据集
        for (user, item, record, timestamp) in data.itertuples(index=False):
            if random.randint(0, 10) == 0:
                self.test_data.setdefault(user, {})
                self.test_data[user][item] = record
            else:
                self.train_data.setdefault(user, {})
                self.train_data[user][item] = record

        self.n_users = len(set(data['user_id'].values))
        self.n_items = len(set(data['item_id'].values))

        print("Initialize end.The user number is:%d,item number is:%d" % (self.n_users, self.n_items))

    def predict(self, user, item):
        rui = 0
        # 分子和分母
        C1 = 0
        C2 = 0
        if not item in self.item_sim:
            return rui
        for interacted_item in self.train_data[user]:
            simi_items = self.item_nei[interacted_item]
            for similar_item, similarity_factor in simi_items:
                if item == similar_item:
                    C1 += similarity_factor * self.train_data[user][interacted_item]
                    C2 += math.fabs(similarity_factor)
        #
        # for similar_item, similarity_factor in sorted(self.item_sim[item].items(),
        #                                               key=itemgetter(1), reverse=True)[:self.K]:
        #     if similar_item not in self.train_data[user]:
        #         continue
        #     C1 += similarity_factor * self.train_data[user][similar_item]
        #     C2 += math.fabs(similarity_factor)
        if not C1 == 0:
            rui = (C1 / C2)
        return rui



parser = argparse.ArgumentParser()
parser.add_argument('--K',type=int, default=20, help='近邻数')
parser.add_argument('--similarityMeasure', default="cosine", help='相似度度量,cosine或pearson')
opt = parser.parse_args()

if __name__ == '__main__':
    model = itemCF("../data/ml-100k/u.data",K=opt.K,similarityMeasure=opt.similarityMeasure)
    ev=evaluate(modelType.rating)
    ev.evaluateModel(model)
    print('done!')

基于用户的协同过滤

import random
import pandas as pd
import numpy as np
import math
from operator import itemgetter
from utils import evaluate
from utils import modelType
import argparse

np.random.seed(1024)


class userCF():
    # 参数:
    # K:近邻数目
    # test_data:测试数据,二维字典。user->item->评分
    # train_data:训练数据
    # n_users:用户数目
    # n_items:项目数目
    # average_rating:每个用户的平均评分、字典。用户->平均评分
    # user_sim:用户之间的相似度。二维字典。u->v->相似度
    # similarityMeasure:相似度度量,cosine或pearson
    def __init__(self, data_file, K=20,similarityMeasure="cosine"):
        self.K = K  # 近邻数
        self.similarityMeasure = similarityMeasure
        self.loadData(data_file)  # 读取数据
        self.initModel()  # 初始化模型

    def initModel(self):
        # 计算每个用户的平均评分
        self.average_rating = {}
        for u, items in self.train_data.items():
            self.average_rating.setdefault(u, 0)
            for i in items:
                self.average_rating[u] += self.train_data[u][i] / len(items)

        # 建立item_user倒排表
        # item->set
        item_users = dict()
        for u, items in self.train_data.items():
            for i in items:
                if i not in item_users:
                    item_users[i] = set()
                item_users[i].add(u)

        # 相似度的分子部分
        C1 = dict()
        C2 = dict()
        C3 = dict()
        for i, users in item_users.items():
            for u in users:
                for v in users:
                    if u == v:
                        continue
                    C1.setdefault(u, {})
                    C1[u].setdefault(v, 0)
                    C2.setdefault(u, {})
                    C2[u].setdefault(v, 0)
                    C3.setdefault(u, {})
                    C3[u].setdefault(v, 0)

                    if self.similarityMeasure == "cosine":
                        C1[u][v] += ((self.train_data[u][i]) * (
                                self.train_data[v][i] ))
                        C2[u][v] += ((self.train_data[u][i]) * (
                                self.train_data[u][i] ))
                        C3[u][v] += ((self.train_data[v][i] ) * (
                                self.train_data[v][i] ))
                    else:
                        C1[u][v] += ((self.train_data[u][i] - self.average_rating[u]) * (
                                self.train_data[v][i] - self.average_rating[v]))
                        C2[u][v] += ((self.train_data[u][i] - self.average_rating[u]) * (
                                self.train_data[u][i] - self.average_rating[u]))
                        C3[u][v] += ((self.train_data[v][i] - self.average_rating[v]) * (
                                self.train_data[v][i] - self.average_rating[v]))

        # 计算最终的用户相似度矩阵
        self.user_sim = dict()
        for u, related_users in C1.items():
            self.user_sim[u] = {}
            for v, cuv in related_users.items():
                # print(C1[u][v],"  ",C2[u][v],"  ",C3[u][v])
                if C1[u][v]==0:
                    self.user_sim[u][v]=0
                else:
                    self.user_sim[u][v] = C1[u][v] / math.sqrt(C2[u][v] * C3[u][v])

    def loadData(self, data_file):
        data_fields = ['user_id', 'item_id', 'rating', 'timestamp']
        data = pd.read_table(data_file, names=data_fields)
        # 二维字典
        self.test_data = {}
        self.train_data = {}

        # 按照1:9划分数据集
        for (user, item, record, timestamp) in data.itertuples(index=False):
            if random.randint(0, 10) == 0:
                self.test_data.setdefault(user, {})
                self.test_data[user][item] = record
            else:
                self.train_data.setdefault(user, {})
                self.train_data[user][item] = record

        self.n_users = len(set(data['user_id'].values))
        self.n_items = len(set(data['item_id'].values))

        print("Initialize end.The user number is:%d,item number is:%d" % (self.n_users, self.n_items))

    def predict(self, user, item):
        rui = self.average_rating[user]
        # 分子和分母
        C1 = 0
        C2 = 0
        for similar_user, similarity_factor in sorted(self.user_sim[user].items(),
                                                      key=itemgetter(1), reverse=True)[0:self.K]:
            if item not in self.train_data[similar_user]:
                continue
            C1 += similarity_factor * (self.train_data[similar_user][item] - self.average_rating[similar_user])
            C2 += math.fabs(similarity_factor)
        if not C1==0:
            rui += (C1 / C2)
        else :
            rui=0
        return rui


parser = argparse.ArgumentParser()
parser.add_argument('--K',type=int, default=20, help='近邻数')
parser.add_argument('--similarityMeasure', default="cosine", help='相似度度量,cosine或pearson')
opt = parser.parse_args()


if __name__ == '__main__':
    model = userCF("../data/ml-100k/u.data",K=opt.K,similarityMeasure=opt.similarityMeasure)
    ev = evaluate(modelType.rating)
    ev.evaluateModel(model)
    print('done!')


执行结果:

在这里插入图片描述
在这里插入图片描述


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值