在推荐系统众多方法中,基于用户的协同过滤推荐算法是最早诞生的,原理也较为简单。该算法1992年提出并用于邮件过滤系统,两年后1994年被 GroupLens 用于新闻过滤。一直到2000年,该算法都是推荐系统领域最著名的算法。

本文简单介绍基于用户的协同过滤算法思想以及原理,最后基于该算法实现园友的推荐,即根据你关注的人,为你推荐博客园中其他你有可能感兴趣的人。基本思想

俗话说“物以类聚、人以群分”,拿看电影这个例子来说,如果你喜欢《蝙蝠侠》、《碟中谍》、《星际穿越》、《源代码》等电影,另外有个人也都喜欢这些电影,而且他还喜欢《钢铁侠》,则很有可能你也喜欢《钢铁侠》这部电影。

所以说,当一个用户 A 需要个性化推荐时,可以先找到和他兴趣相似的用户群体 G,然后把 G 喜欢的、并且 A 没有听说过的物品推荐给 A,这就是基于用户的系统过滤算法。原理

根据上述基本原理,我们可以将基于用户的协同过滤推荐算法拆分为两个步骤:

1. 找到与目标用户兴趣相似的用户集合

2. 找到这个集合中用户喜欢的、并且目标用户没有听说过的物品推荐给目标用户

1.发现兴趣相似的用户

通常用 Jaccard 公式或者余弦相似度计算两个用户之间的相似度。设 N(u) 为用户 u 喜欢的物品集合,N(v) 为用户 v 喜欢的物品集合,那么 u 和 v 的相似度是多少呢:

Jaccard 公式:

余弦相似度:

假设目前共有4个用户: A、B、C、D;共有5个物品:a、b、c、d、e。用户与物品的关系(用户喜欢物品)如下图所示:

如何一下子计算所有用户之间的相似度呢?为计算方便,通常首先需要建立“物品—用户”的倒排表,如下图所示:

然后对于每个物品,喜欢他的用户,两两之间相同物品加1。例如喜欢物品 a 的用户有 A 和 B,那么在矩阵中他们两两加1。如下图所示:

计算用户两两之间的相似度,上面的矩阵仅仅代表的是公式的分子部分。以余弦相似度为例,对上图进行进一步计算:

到此,计算用户相似度就大功告成,可以很直观的找到与目标用户兴趣较相似的用户。

2.推荐物品

首先需要从矩阵中找出与目标用户 u 最相似的 K 个用户,用集合 S(u, K) 表示,将 S 中用户喜欢的物品全部提取出来,并去除 u 已经喜欢的物品。对于每个候选物品 i ,用户 u 对它感兴趣的程度用如下公式计算:

其中 rvi 表示用户 v 对 i 的喜欢程度,在本例中都是为 1,在一些需要用户给予评分的推荐系统中,则要代入用户评分。

举个例子,假设我们要给 A 推荐物品,选取 K = 3 个相似用户,相似用户则是:B、C、D,那么他们喜欢过并且 A 没有喜欢过的物品有:c、e,那么分别计算 p(A, c) 和 p(A, e):

看样子用户 A 对 c 和 e 的喜欢程度可能是一样的,在真实的推荐系统中,只要按得分排序,取前几个物品就可以了。

在社交网络的推荐中,“物品”其实就是“人”,“喜欢一件物品”变为“关注的人”,这一节用上面的算法实现给我推荐 10 个园友。

1.计算10名与我兴趣最相似的园友

由于只是为我一个人做用户推荐,所以没必要建立一个庞大的用户两两之间相似度的矩阵了,与我兴趣相似的园友只会在这个群体产生:我关注的人的粉丝。除我自己之外,目前我一共关注了23名园友,这23名园友一共有22936个唯一粉丝,我对这22936个用户逐一计算了相似度,相似度排名前10的用户及相似度如下:

昵称

关注数量

共同数量

相似度

蓝枫叶1938

5

4

0.373001923296126

FBI080703

3

3

0.361157559257308

鱼非鱼

3

3

0.361157559257308

Lauce

3

3

0.361157559257308

蓝色蜗牛

3

3

0.361157559257308

shanyujin

3

3

0.361157559257308

Mr.Huang

6

4

0.340502612303499

对世界说你好

6

4

0.340502612303499

strucoder

28

8

0.31524416249564

Mr.Vangogh

4

3

0.312771621085612

2.计算对推荐园友的兴趣度

这10名相似用户一共推荐了25名园友,计算得到兴趣度并排序:

排序

昵称

兴趣度

1

wolfy

0.373001923296126

2

Artech

0.340502612303499

3

Cat Chen

0.340502612303499

4

WXWinter(冬)

0.340502612303499

5

DanielWise

0.340502612303499

6

一路前行

0.31524416249564

7

Liam Wang

0.31524416249564

8

usharei

0.31524416249564

9

CoderZh

0.31524416249564

10

博客园团队

0.31524416249564

11

深蓝色右手

0.31524416249564

12

Kinglee

0.31524416249564

13

Gnie

0.31524416249564

14

riccc

0.31524416249564

15

Braincol

0.31524416249564

16

滴答的雨

0.31524416249564

17

Dennis Gao

0.31524416249564

18

刘冬.NET

0.31524416249564

19

李永京

0.31524416249564

20

浪端之渡鸟

0.31524416249564

21

李涛

0.31524416249564

22

阿不

0.31524416249564

23

JK_Rush

0.31524416249564

24

xiaotie

0.31524416249564

25

Leepy

0.312771621085612

只需要按需要取相似度排名前10名就可以了,不过看起来整个列表的推荐质量都还不错!

具体代码实现:

#-*- coding: utf-8 -*-

'''''

Created on 2015-06-22

@author: Lockvictor

'''

import sys

import random

import math

import os

from operator import itemgetter

from collections import defaultdict

random.seed(0)

'''''

users.dat 数据集

用户id 用户性别 用户年龄 用户职业 用户所在地邮编

1::F::1::10::48067

2::M::56::16::70072

3::M::25::15::55117

movies.dat 数据集

电影id 电影名称 电影类型

250::Heavyweights (1994)::Children's|Comedy

251::Hunted, The (1995)::Action

252::I.Q. (1994)::Comedy|Romance

ratings.dat 数据集

用户id 电影id 用户评分  时间戳

157::3519::4::1034355415

157::2571::5::977247494

157::300::3::977248224

'''

class UserBasedCF(object):

''''' TopN recommendation - User Based Collaborative Filtering '''

# 构造函数,用来初始化

def __init__(self):

# 定义 训练集 测试集 为字典类型

self.trainset = {}

self.testset = {}

# 训练集用的相似用户数

self.n_sim_user = 20

# 推荐电影数量

self.n_rec_movie = 10

self.user_sim_mat = {}

# 表示电影的流行度,有一个看过该电影,流行度+1,没有人看过,流行度的值默认为0

self.movie_popular = {}

# 记录电影数量

self.movie_count = 0

# sys.stderr 是用来重定向标准错误信息的

print ('相似用户数目为 = %d' % self.n_sim_user, file=sys.stderr)

print ('推荐电影数目为 = %d' %

self.n_rec_movie, file=sys.stderr)

# 加载文件

@staticmethod

def loadfile(filename):

''''' load a file, return a generator. '''

# 以只读的方式打开传入的文件

fp = open(filename, 'r')

# enumerate()为枚举,i为行号从0开始,line为值

for i, line in enumerate(fp):

# yield 迭代去下一个值,类似next()

# line.strip()用于去除字符串头尾指定的字符。

yield line.strip('\r\n')

# 计数

if i % 100000 == 0:

print ('loading %s(%s)' % (filename, i), file=sys.stderr)

fp.close()

# 打印加载文件成功

print ('load %s succ' % filename, file=sys.stderr)

# 划分训练集和测试集 pivot用来定义训练集和测试集的比例

def generate_dataset(self, filename, pivot=0.7):

''''' load rating data and split it to training set and test set '''

trainset_len = 0

testset_len = 0

for line in self.loadfile(filename):

# 根据 分隔符 :: 来切分每行数据

user, movie, rating, _ = line.split('::')

# 随机数字 如果小于0.7 则数据划分为训练集

if random.random()

# 设置训练集字典,key为user,value 为字典 且初始为空

self.trainset.setdefault(user, {})

# 以下省略格式如下,集同一个用户id 会产生一个字典,且值为他评分过的所有电影

#{'1': {'914': 3, '3408': 4, '150': 5, '1': 5}, '2': {'1357': 5}}

self.trainset[user][movie] = int(rating)

trainset_len += 1

else:

self.testset.setdefault(user, {})

self.testset[user][movie] = int(rating)

testset_len += 1

# 输出切分训练集成功

print ('划分数据为训练集和测试集成功!', file=sys.stderr)

# 输出训练集比例

print ('训练集数目 = %s' % trainset_len, file=sys.stderr)

# 输出测试集比例

print ('测试集数目 = %s' % testset_len, file=sys.stderr)

# 建立物品-用户 倒排表

def calc_user_sim(self):

''''' calculate user similarity matrix '''

# build inverse table for item-users

# key=movieID, value=list of userIDs who have seen this movie

print ('构建物品-用户倒排表中,请等待......', file=sys.stderr)

movie2users = dict()

# Python 字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组

for user, movies in self.trainset.items():

for movie in movies:

# inverse table for item-users

if movie not in movie2users:

# 根据电影id 构造set() 函数创建一个无序不重复元素集

movie2users[movie] = set()

# 集合中值为用户id

# 数值形如

# {'914': {'1','6','10'}, '3408': {'1'} ......}

movie2users[movie].add(user)

# 记录电影的流行度

if movie not in self.movie_popular:

self.movie_popular[movie] = 0

self.movie_popular[movie] += 1

print ('构建物品-用户倒排表成功', file=sys.stderr)

# save the total movie number, which will be used in evaluation

self.movie_count = len(movie2users)

print ('总共被操作过的电影数目为 = %d' % self.movie_count, file=sys.stderr)

# count co-rated items between users

usersim_mat = self.user_sim_mat

print ('building user co-rated movies matrix...', file=sys.stderr)

# 令系数矩阵 C[u][v]表示N(u)∩N(v) ,假如用户u和用户v同时属于K个物品对应的用户列表,就有C[u][v]=K

for

, users in movie2users.items():

for u in users:

usersim_mat.setdefault(u, defaultdict(int))

for v in users:

if u == v:

continue

usersim_mat[u][v] += 1

print ('build user co-rated movies matrix succ', file=sys.stderr)

# calculate similarity matrix

print ('calculating user similarity matrix...', file=sys.stderr)

# 记录计算用户兴趣相似度的次数

simfactor_count = 0

# 计算用户兴趣相似度复杂度上限值

PRINT_STEP = 2000000

# 循环遍历usersim_mat 根据余弦相似度公式计算出用户兴趣相似度

for u, related_users in usersim_mat.items():

for v, count in related_users.items():

# 以下是公式计算过程

usersim_mat[u][v] = count / math.sqrt(

len(self.trainset[u]) * len(self.trainset[v]))

#计数 并没有什么卵用

simfactor_count += 1

if simfactor_count % PRINT_STEP == 0:

print ('calculating user similarity factor(%d)' %

simfactor_count, file=sys.stderr)

print ('calculate user similarity matrix(similarity factor) succ',

file=sys.stderr)

print ('Total similarity factor number = %d' %

simfactor_count, file=sys.stderr)

# 根据用户给予推荐结果

def recommend(self, user):

'''''定义给定K个相似用户和推荐N个电影'''

K = self.n_sim_user

N = self.n_rec_movie

# 定义一个字典来存储为用户推荐的电影

rank = dict()

# 使用watched_movies来表示用户看过的电影列表,后续在做推荐电影需要排除掉用户看过的电影

watched_movies = self.trainset[user]

# sorted() 函数对所有可迭代的对象进行排序操作。 key 指定比较的对象 ,reverse=True 降序,这里user_sim_mat好像应该换成usersim_mat

for similar_user, similarity_factor in sorted(self.user_sim_mat[user].items(),

key=itemgetter(1), reverse=True)[0:K]:

for movie in self.trainset[similar_user]:

# 判断 如果这个电影 该用户已经看过 则跳出循环

if movie in watched_movies:

continue

# 记录用户对推荐的电影的兴趣度,这里的兴趣度也是根据该用户与推荐用户的相似度来定的

rank.setdefault(movie, 0)

rank[movie] += similarity_factor

# return the N best movies

return sorted(rank.items(), key=itemgetter(1), reverse=True)[0:N]

# 计算 准确率,召回率,覆盖率,流行度

def evaluate(self):

''''' print evaluation result: precision, recall, coverage and popularity '''

print ('Evaluation start...', file=sys.stderr)

N = self.n_rec_movie

#  varables for precision and recall

#记录推荐正确的电影数

hit = 0

#记录推荐电影的总数

rec_count = 0

#记录测试数据中总数

test_count = 0

# varables for coverage

all_rec_movies = set()

# varables for popularity

popular_sum = 0

for i, user in enumerate(self.trainset):

if i % 500 == 0:

print ('recommended for %d users' % i, file=sys.stderr)

test_movies = self.testset.get(user, {})

rec_movies = self.recommend(user)

for movie, _ in rec_movies:

if movie in test_movies:

hit += 1

all_rec_movies.add(movie)

popular_sum += math.log(1 + self.movie_popular[movie])

rec_count += N

test_count += len(test_movies)

# 计算准确度

precision = hit / (1.0 * rec_count)

# 计算召回率

recall = hit / (1.0 * test_count)

# 计算覆盖率

coverage = len(all_rec_movies) / (1.0 * self.movie_count)

#计算流行度

popularity = popular_sum / (1.0 * rec_count)

print ('precision=%.4f\trecall=%.4f\tcoverage=%.4f\tpopularity=%.4f' %

(precision, recall, coverage, popularity), file=sys.stderr)

if __name__ == '__main__':

ratingfile = os.path.join('ml-1m', 'ratings.dat')

usercf = UserBasedCF()

usercf.generate_dataset(ratingfile)

usercf.calc_user_sim()

'''''

以下为用户id 为 1688的用户推荐的电影

a = usercf.recommend("1688")

[('1210', 3.1260082382168055), ('2355', 3.0990860017403934), ('1198', 2.692208437663706), ('1527', 2.643102457311887), ('3578', 2.61895974438311), ('1376', 2.469905776632142), ('110', 2.4324588006133383), ('1372', 2.4307454264036528), ('1240', 2.424265305355254), ('32', 2.3926144836965966)]

'''

usercf.evaluate()

python协同过滤可以预测吗_基于用户的协同过滤推荐算法原理-附python代码实现...相关推荐

  1. 基于用户行为分析的推荐算法

    文章目录 基于用户行为分析的推荐算法 用户行为数据简介 用户行为分析 用户活跃度和物品流行度的分布 用户活跃度和物品流行度的关系 实验设计和算法测评 数据集 实验设计 评测指标 基于领域的算法 基于用 ...

  2. 基于用户行为特征的推荐算法

    简述:基于用户行为分析的推荐算法是个性化推荐系统的重要算法,也被称为协同过滤算法,即通过用户与网站不断互动,来不断过滤自己感兴趣的物品. 基础概念 用户行为分类 按照反馈的明确性分 显性反馈行为: 用 ...

  3. 协同过滤算法_基于用户的协同过滤推荐算法原理和实现

    (给算法爱好者加星标,修炼编程内功) 来源:Create Chen's Blog https://www.cnblogs.com/technology/p/4467895.html 在推荐系统众多方法 ...

  4. java 用户协同过滤算法_基于用户的协同过滤推荐算法java实现(UserCF)

    UserCF的核心思想即为根据用户数据模拟向量相似度,我们根据这个相似度,来找出指定用户的相似用户,然后将相似用户买过的而指定用户没有买的东西推荐给指定用户,推荐度的计算也是结合了相似用户与指定用户的 ...

  5. python重点知识归纳_一文了解机器学习知识点及其算法(附python代码)

    一文了解机器学习知识点及其算法(附python代码) 来源:数据城堡 时间:2016-09-09 14:05:50 作者: 机器学习发展到现在,已经形成较为完善的知识体系,同时大量的数据科学家的研究成 ...

  6. 基于用户的电视节目推荐算法实例

    # -*- coding: utf-8 -*- """ Created on Thu Nov 1 10:29:52 2018@author: AZ "" ...

  7. python对电影进行预测评分_基于R语言构建的电影评分预测模型

    原标题:基于R语言构建的电影评分预测模型 欢迎关注天善智能 hellobi.com,我们是专注于商业智能BI,大数据,数据分析领域的垂直社区,学习.问答.求职,一站式搞定! 对商业智能BI.大数据分析 ...

  8. python人脸识别系统界面设计_基于卷积神经网络的人脸识别系统的设计(Python)

    基于卷积神经网络的人脸识别系统的设计(Python)(论文10000字,外文翻译,参考代码,流程图,人脸图像库) 摘要:随着社会的进步与发展,个人信息的保护变得十分重要.传统的密码保护方式已经不再满足 ...

  9. MATLAB实战系列(二十一)-基于遗传算法的BP神经网络优化算法(附MATLAB代码)

    前言 如何用matlab搭建一个简单的Bp神经网络,并且在代码的最后得到Bp神经网络训练后的权值与阈值.实际上,权值与阈值可以在开始训练网络前给其赋值,换句话说,我们给神经网络的权值与阈值想怎么赋值就 ...

最新文章

  1. mysql repair 索引_mysql 创建索引、重建索引、查询索引、删除索引 转自:http://www.phpernote.com/mysql/942.html...
  2. centos 安装 rabbitMq
  3. MY Fist 51CTO BLOG
  4. yolo算法_吴恩达深度学习笔记(100)-目标检测之YOLO 算法讲解
  5. 使用JavaScript的图像识别游戏
  6. 面向大数据处理应用的广域存算协同调度系统
  7. opencv-api adaptiveThreshold
  8. new 失败的处理方式
  9. HDFS-HA的配置-----自动Failover
  10. 笑傲江湖手3D游服务器端文件,武林大会即将拉开序幕《笑傲江湖3D手游》12月公测来袭...
  11. mybatis的多AND条件查询。批量插入。String分割查询。
  12. JavaSE复习_6 枚举类
  13. linux 同步utc时间吗,中国时区utc在服务器上同步的办法
  14. wifidog 源码初分析
  15. python 解析域名
  16. ASR—音频数据断句切割
  17. 突发奇想 之 古玩中的代码
  18. AT32F437基于LVGL的桌面显示案例
  19. 步行速度快慢测试软件,超准!风靡跑圈的5公里跑步测试,进来看看你是哪个等级!...
  20. 机器学习参数|数学建模|自相关性

热门文章

  1. 酷狗计算机自动续费,怎么取消酷狗自动续费-APP自动续费关不了?可在微信支付宝这样操作!...
  2. [系统安全] 三十五.Procmon工具基本用法及文件进程、注册表查看
  3. Taobao api, Jingdong api, 1688api, Pinduoduo api, Douyin api commodity interface source code
  4. 使用cmake搭建一个跨平台游戏服务器
  5. 计算机字体对于现代设计有何意义,创意字体在现代设计中的重要性
  6. 发布:世界上第一个小米平板4上的Debian Linux 刷机包
  7. 设计模式与软件体系结构复习资料——设计模式
  8. 彩色模型RGB,HSI,HSV,CMYK区分
  9. 关系型数据库的瓶颈 与 优化
  10. 0x80004005