推荐系统简介之一(itemCF算法)
  习惯了今日头条、网易云音乐的推荐,对其背后的推荐原理产生了兴趣,大致了解了一下,主要利用用户上下文信息,比如注册信息、社交好友、时间地点、用户行为(购买、浏览记录等),来进行相关的分析。
  目前比较流行的推荐算法有userCF、itemCF、SVD++等。
  对于电商类网站,基于物品的协同过滤(item-based collaborative filtering)算法是目前业界应用最多的算法,如Amazon等。
  itemCF思想:给用户推荐那些和他们之前喜欢的物品相似的物品。
  (1) 计算物品之间的相似度。
  (2) 根据物品的相似度和用户的历史行为给用户生成推荐列表。
  
  itemCF算法具体过程:
  1、构建M*N矩阵,N为用户数,M为item数,矩阵中数值rji表示用户i对item j的打分项。
  2、计算item i与item j的相似度,可以采用余弦相似度进行计算。
  余弦相似度定义
  为增强数值范围的健壮性,通常对每个item的N个user的打分值进行归一化,即每个user的打分值减去该item项的平均打分值。
  为避免未打分的user与item项影响,通常仅取矩阵中的item i与item j的公共用户的打分值进行相似度计算。
  相似度计算时,矩阵中打分数据通常并不进行归一化操作,如下面代码所示,而是直接计算,这时公式需要变形为下式:
  代码中余弦相似度的计算
  3、对用户x的待预测各item i,预测打分值,打分值按照最相似的topN个物品的加权打分和进行计算:
  预测值计算
  top N可以固定参数N,也可以设置门限,仅取相似度高于门限的参与计算。用movielens 100w数据集测试,N=10左右有较好效果。
  这样就完成了预测,从而可以将预测打分值高于门限的item项推荐展示给用户。
  
  下面代码来自于justdark/dml,添加了部分注释.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from __future__ import division
import numpy as np
import scipy as sp
class Item_based_C:
def __init__(self,X):
self.X=np.array(X)
print "the input data size is ",self.X.shape
self.movie_user={}
self.user_movie={}
self.ave=np.mean(self.X[:,2])
for i in range(self.X.shape[0]):
uid=self.X[i][0]
mid=self.X[i][2]
rat=self.X[i][3]
self.movie_user.setdefault(mid,{})
self.user_movie.setdefault(uid,{})
self.movie_user[mid][uid]=rat
self.user_movie[uid][mid]=rat
self.similarity={}
pass
def sim_cal(self,m1,m2):
self.similarity.setdefault(m1,{})
self.similarity.setdefault(m2,{})
self.movie_user.setdefault(m1,{})
self.movie_user.setdefault(m2,{})
self.similarity[m1].setdefault(m2,-1)
self.similarity[m2].setdefault(m1,-1)
if self.similarity[m1][m2]!=-1:
return self.similarity[m1][m2]
si={}
for user in self.movie_user[m1]: # itme m1 and item target m2 ,common user set si =1
if user in self.movie_user[m2]:
si[user]=1
n=len(si)
if (n==0):
self.similarity[m1][m2]=1
self.similarity[m2][m1]=1
return 1
s1=np.array([self.movie_user[m1][u] for u in si]) # item j, common user
s2=np.array([self.movie_user[m2][u] for u in si]) # item target mid, common user
sum1=np.sum(s1)
sum2=np.sum(s2)
sum1Sq=np.sum(s1**2)
sum2Sq=np.sum(s2**2)
pSum=np.sum(s1*s2)
num=pSum-(sum1*sum2/n) # equal to sum[(s1-aveS1)*(s2-aveS2)]
den=np.sqrt((sum1Sq-sum1**2/n)*(sum2Sq-sum2**2/n))
if den==0:
self.similarity[m1][m2]=0
self.similarity[m2][m1]=0
return 0
self.similarity[m1][m2]=num/den
self.similarity[m2][m1]=num/den
return num/den
def pred(self,uid,mid):
sim_accumulate=0.0
rat_acc=0.0
for item in self.user_movie[uid]: # only fetch rating[item][uid]!=0, avoid cal all item
sim=self.sim_cal(item,mid) # sji, i=mid
if sim<0:continue
#print sim,self.user_movie[uid][item],sim*self.user_movie[uid][item]
rat_acc+=sim*self.user_movie[uid][item] # weight sum all non-zero items, Sij*rjx
sim_accumulate+=sim # sum(sij)
#print rat_acc,sim_accumulate
if sim_accumulate==0: #no same user rated,return average rates of the data
return self.ave
return rat_acc/sim_accumulate
def test(self,test_X):
test_X=np.array(test_X)
output=[]
sums=0
bersum=0
ber=0
print "the test data size is ",test_X.shape
for i in range(test_X.shape[0]):
pre=self.pred(test_X[i][0],test_X[i][4])
output.append(pre)
#print pre,test_X[i][5]
sums+=(pre-test_X[i][6])**2
bersum+=np.abs(pre-test_X[i][7])/test_X[i][8]
rmse=np.sqrt(sums/test_X.shape[0])
ber = bersum/test_X.shape[0]
print "the rmse on test data is ",rmse
print "the precision error percent on test data is ",ber
return output

  使用movielens 100k验证,结果如下:

1
2
3
the test data size is (20000, 3)
the rmse on test data is 1.04164917355
the precision error percent on test data is 0.338795947635

参考资料:
【1】《推荐系统实践》,项亮编著
【2】推荐系统与应用,CSDN blog