欢迎使用CSDN-markdown编辑器

来源:互联网 发布:网络认证怎么弄 编辑:程序博客网 时间:2024/05/20 09:08
基于用户的协同过滤算法也被称为最近邻协同过滤或KNN (K.Nearest-Neighbor,K最近邻算法)。其核心思想就是,首先根据相似度计算出目标用户的邻居。1.首先,使用用户已有的评分来计算用户之间的相似度;2.然后,选择与目标用户相似度最高的K个用户,通常把这些用户称为邻居;3.最后,通过对邻居用户的评分的加权平均来预测目标用户的评分。为了方便说明,我们把系统中用户的集合记为U。物品的集合记为I,用户u,v∈U,物品i,j∈I, 是用户对物品的评分,而用户u和v之间的相似度记为 ,用一个m×n的矩阵来表示所个用户对玎个物品的评分情况。读入数据集,此时建立users字典,以第一列用户名为key,新建一个字典为value,value字典以书籍id为key,以对书籍的评分为value。以皮尔逊相似度来计算两用户之间的相似度,计算公式如下

皮尔逊相似度

# -*- coding: utf-8 -*-"""Created on Thu Nov 23 16:30:43 2017@author: BruceKun"""from math import sqrt  fp = open("f:/data.txt","r",encoding='utf8')  users = {}  for line in open("f:/data.txt",encoding='utf8'):      lines = line.strip().split(",")      if lines[0] not in users:  #用户名没在用户名字典里就将用户名加入        users[lines[0]] = {}   #以用户名为key的字典新建一个字典    users[lines[0]][lines[2]]=float(lines[1])  #用户名字典以书id为key,书评分为value#----------------新增代码段END----------------------  class recommender:      #data:数据集,这里指users      #k:表示得出最相近的k的近邻      #metric:表示使用计算相似度的方法      #n:表示推荐book的个数      def __init__(self, data, k=3, metric='pearson', n=12):          self.k = k          self.n = n          self.username2id = {}          self.userid2name = {}          self.productid2name = {}          self.metric = metric          if self.metric == 'pearson':              self.fn = self.pearson          if type(data).__name__ == 'dict':              self.data = data      def convertProductID2name(self, id):          if id in self.productid2name:              return self.productid2name[id]          else:              return id      #定义的计算相似度的公式,用的是皮尔逊相关系数计算方法      def pearson(self, rating1, rating2):          sum_xy = 0  #分子相乘        sum_x = 0   #分子前半部分        sum_y = 0   #分子后半部分        sum_x2 = 0  #分母前半部分        sum_y2 = 0  #分母后半部分        n = 0          #rating为用户表,此处key为书id        for key in rating1:              if key in rating2:                  n += 1  #n为共同评分数量                x = rating1[key]  #x,y为书的评分                y = rating2[key]                  sum_xy += x * y                  sum_x += x                  sum_y += y                  sum_x2 += pow(x, 2)                  sum_y2 += pow(y, 2)          if n == 0:              return 0          #皮尔逊相关系数计算公式           denominator = sqrt(sum_x2 - pow(sum_x, 2) / n)  * sqrt(sum_y2 - pow(sum_y, 2) / n)          if denominator == 0:              return 0          else:              return (sum_xy - (sum_x * sum_y) / n) / denominator      def computeNearestNeighbor(self, username):          distances = []          for instance in self.data:  #self.data为用户名数据集            if instance != username:                  distance = self.fn(self.data[username],self.data[instance])                  distances.append((instance, distance))          distances.sort(key=lambda artistTuple: artistTuple[1],reverse=True)          return distances      #推荐算法的主体函数      def recommend(self, user):          #定义一个字典,用来存储推荐的书单和分数          recommendations = {}          #计算出user与所有其他用户的相似度,返回一个list          nearest = self.computeNearestNeighbor(user)          # print nearest          userRatings = self.data[user]          # print userRatings          totalDistance = 0.0          #得住最近的k个近邻的总距离          for i in range(self.k):              totalDistance += nearest[i][1]          if totalDistance==0.0:              totalDistance=1.0          #将与user最相近的k个人中user没有看过的书推荐给user,并且这里又做了一个分数的计算排名          for i in range(self.k):              #第i个人的与user的相似度,转换到[0,1]之间              weight = nearest[i][1] / totalDistance              #第i个人的name              name = nearest[i][0]              #第i个用户看过的书和相应的打分              neighborRatings = self.data[name]              for artist in neighborRatings:                  if not artist in userRatings:#用户打分                    if artist not in recommendations:  #书单中没有                        recommendations[artist] = (neighborRatings[artist] * weight)                      else:                          recommendations[artist] = (recommendations[artist]+ neighborRatings[artist] * weight)          recommendations = list(recommendations.items())          recommendations = [(self.convertProductID2name(k), v)for (k, v) in recommendations]          #做了一个排序          recommendations.sort(key=lambda artistTuple: artistTuple[1], reverse = True)          return recommendations[:self.n],nearest  def adjustrecommend(id):      bookid_list = []      r = recommender(users)      k,nearuser = r.recommend("%s" % id)      for i in range(len(k)):          bookid_list.append(k[i][0])      return bookid_list,nearuser[:15]        #bookid_list推荐书籍的id,nearuser[:15]最近邻的15个用户 bookid_list,near_list = adjustrecommend("欧阳杼")  print ("bookid_list:",bookid_list)  print ("near_list:",near_list) 

数据集格式如下,用户名、评分、书籍id,中间用逗号隔开

数据集格式

因为数据量较小,与用户相似度近似的只有一个而且完全相同,所以不存在为该用户推荐相似用户看过该用户没有看过的书目
推荐结果:
这里写图片描述

原创粉丝点击