基于邻域的top-N推荐

原理:

1、基于用户的协同过滤算法(user-based CF)
一个用户喜欢和他具有相似喜好的用户喜欢的项目, 两个用户喜欢的项目交集越大, 这两个用户越相似。
两个用户兴趣相似度的计算可以有多种方法,使用Pearson相关相似性和余弦相似度计算。
2、基于项目的协同过滤
基于项目的协同过滤推荐(item-based CF)基于这样的假设[8]: 一个用户会喜欢与他之前喜欢的项目相似的项目。因此, 基于项目的协同过滤推荐关键在于计算物品之间的相似度。
基于用户的协同过滤和基于项目的协同过滤统称为基于邻域的推荐 (nearest neighbor recommendation),也称作基于记忆的推荐算法(memory-based recommendation)。
基于邻域的推荐算法需要维护一个用户相似度矩阵或项目相似度矩阵, 因此对于项目的数目更新速度远远小于用户数目的增长速度的情况, 宜采用基于项目的推荐算法, 如 Amazon 建立的推荐系统正是基于项目的协同过滤推荐算法[5], 还有移动应用产品的推荐。另外, 有研究表明, 基于项目的算法一般在性能上要优于基于用户的算法基于领域的推荐算法不足之处在于数据稀疏性等问题, 难以处理大数据量下的即时结果。因此提出了基于模型的协同过滤推荐算法。


基于用户的协同过滤算法

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

np.random.seed(1024)


class itemCF():
    # 参数:
    # K:近邻数目
    # N:物品推荐数目
    # test_data:测试数据,二维字典。user->item->评分
    # train_data:训练数据
    # n_users:用户数目
    # n_items:项目数目
    # item_sim:项目之间的相似度。二维字典。i->j->相似度
    # similarityMeasure:相似度度量,cosine或conditional
    def __init__(self, data_file, K=20,N=10,similarityMeasure="cosine"):
        self.K = K  # 近邻数
        self.N = N  # 物品推荐数
        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

        # 计算物品之间共同评分的物品数,C为修正后的,count为修正前的。
        C = dict()
        count=dict()
        for user, items in self.train_data.items():
            for u in items:
                for v in items:
                    if u == v:
                        continue
                    C.setdefault(u,{})
                    C[u].setdefault(v,0)
                    C[u][v] += math.log(self.n_items/len(items))

                    count.setdefault(u, {})
                    count[u].setdefault(v, 0)
                    count[u][v] += 1
        # 计算最终的物品相似度矩阵
        self.item_sim = dict()
        for u, related_items in C.items():
            self.item_sim[u]={}
            for v, cuv in related_items.items():
                if self.similarityMeasure=="cosine":
                    self.item_sim[u][v] = cuv / math.sqrt(item_cnt[u] * item_cnt[v])
                else:
                    self.item_sim[u][v] = count[u][v] / (item_cnt[u])

    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):
        rank = dict()
        interacted_items = self.train_data[user]

        # 对每个评分的物品寻找最近K个物品,构建评分列表
        for item, rating in interacted_items.items():
            for similar_item, similarity_factor in sorted(self.item_sim[item].items(),
                                                           key=itemgetter(1), reverse=True)[:self.K]:
                if similar_item in interacted_items:
                    continue
                rank.setdefault(similar_item, 0)
                # rank[similar_item] += similarity_factor * rating
                rank[similar_item] += similarity_factor

        rec_list = []
        rec_items = sorted(rank.items(), key=itemgetter(1), reverse=True)[0:self.N]
        for item, score in rec_items:
            rec_list.append(item)

        # 返回最大N个物品
        return rec_list

parser = argparse.ArgumentParser()
parser.add_argument('--K',type=int, default=20, help='近邻数')
parser.add_argument('--N',type=int, default=10, help='物品推荐数')
parser.add_argument('--similarityMeasure', default="cosine", help='相似度度量,cosine或conditional')
opt = parser.parse_args()


if __name__ == '__main__':
    model = itemCF("../data/ml-100k/u.data",K=opt.K,N=opt.N,similarityMeasure=opt.similarityMeasure)
    ev = evaluate(modelType.topN)
    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:近邻数目
    # N:物品推荐数目
    # test_data:测试数据,二维字典。user->item->评分
    # train_data:训练数据
    # n_users:用户数目
    # n_items:项目数目
    # user_sim:用户之间的相似度。二维字典。u->v->相似度
    # similarityMeasure:相似度度量,cosine或jaccard
    def __init__(self, data_file, K=20,N=10,similarityMeasure="cosine"):
        self.K = K  # 近邻数
        self.N = N  # 物品推荐数
        self.similarityMeasure = similarityMeasure
        self.loadData(data_file)    # 读取数据
        self.initModel()            # 初始化模型

    def initModel(self):
        # 建立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)

        # 计算用户之间共同评分的物品数,C为修正后的,count为修正前的。
        C = dict()
        count = dict()
        for i, users in item_users.items():
            for u in users:
                for v in users:
                    if u == v:
                        continue
                    C.setdefault(u,{})
                    C[u].setdefault(v,0)
                    # 对热门物品进行惩罚
                    C[u][v] += math.log(self.n_users/len(users))
                    # 计算最终的用户相似度矩阵

                    count.setdefault(u, {})
                    count[u].setdefault(v, 0)
                    count[u][v] += 1
        self.user_sim = dict()
        for u, related_users in C.items():
            self.user_sim[u]={}
            for v, cuv in related_users.items():
                if self.similarityMeasure == "cosine":
                    self.user_sim[u][v] = cuv / math.sqrt(len(self.train_data[u]) * len(self.train_data[v]))
                else:
                    self.user_sim[u][v] = count[u][v] / (len(self.train_data[u])+len(self.train_data[v])-count[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):
        rank = dict()
        interacted_items = self.train_data[user]

        # 寻找最近的K个用户,利用它们的评分信息构造推荐列表
        for similar_user, similarity_factor in sorted(self.user_sim[user].items(),
                                                      key=itemgetter(1), reverse=True)[0:self.K]:
            for movie in self.train_data[similar_user]:
                if movie in interacted_items:
                    continue
                rank.setdefault(movie, 0)
                # rank[movie] += similarity_factor*self.train_data[similar_user][movie]
                rank[movie] += similarity_factor

        rec_list=[]
        rec_items=sorted(rank.items(), key=itemgetter(1), reverse=True)[0:self.N]
        for item,score in rec_items:
            rec_list.append(item)
        return rec_list

parser = argparse.ArgumentParser()
parser.add_argument('--K',type=int, default=20, help='近邻数')
parser.add_argument('--N',type=int, default=10, help='物品推荐数')
parser.add_argument('--similarityMeasure', default="cosine", help='相似度度量,cosine或jaccard')
opt = parser.parse_args()


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


原因分析:

提示:这里填写问题的分析:

例如:Handler 发送消息有两种方式,分别是 Handler.obtainMessage()Handler.sendMessage(),其中 obtainMessage 方式当数据量过大时,由于 MessageQuene 大小也有限,所以当 message 处理不及时时,会造成先传的数据被覆盖,进而导致数据丢失。


执行结果:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值