协同过滤算法
协同过滤算法(Collaborative Filtering, CF)是很常用的一种算法,在很多电商网站上都有用到。CF算法包括基于用户的CF(User-based CF)和基于物品的CF(Item-based CF)。
基于用户的协同过滤算法
基于用户的CF原理如下:
1. 分析各个用户对item的评价(通过浏览记录、购买记录等);
2. 依据用户对item的评价计算得出所有用户之间的相似度;
3. 选出与当前用户最相似的N个用户;
4. 将这N个用户评价最高并且当前用户又没有浏览过的item推荐给当前用户。
类似下图:
基于物品的协同过滤算法
基于物品的CF原理大同小异,只是主体在于物品:
1. 分析各个用户对item的浏览记录。
2. 依据浏览记录分析得出所有item之间的相似度;
3. 对于当前用户评价高的item,找出与之相似度最高的N个item;
4. 将这N个item推荐给用户
类似下图:
相似度的度量方法
相似性的度量方法必须满足拓扑学中的度量空间的基本条件:假设d是度量空间M上的度量
:,其中度量d满足:
第一种相似性度量方法:欧氏距离
第二种相似性度量方法:皮尔逊相关系数
在欧氏距离中,不同特征之间的量级的影响较大,入A(0.05,1),B(1,1),C(0.05,4)AB之间距离是0.95,AC之间距离是3,此时不能很好的判断AB,AC之间相似性的大小(WHY)。皮尔逊相关系数计算公式如下:
皮尔逊相似度对量级不敏感,AB之间为0.5186,AC之间为-0.4211.
第三种相似性度量方法:余弦相似度
余弦相似度是文本相似度度量中使用较多的一种方法
越接近1表示相似度越大
例如:
原始数据:下图行是用户对每一种商品的一个评价分数,利用用户-商品矩阵计算用户相似度矩阵w,w(i,j)代表的是用户i和j的相似度。然后利用不同用户之间的相似度,将商品推荐给用户。
表1用户-商品矩阵
表2用户相似度矩阵
对于用户0来说,没有评价过2,4号商品。所以0号用户对2号商品的推荐值为
,N(i)是对商品i评价过的用户的集合,Wu,v是用户u,v之间的相关度,Rv,i用户v对商品i的评价。如0号用户对2号商品的推荐值 =0.749269*4 + 0.32*5 + 0.252982*2 = 5.10284,对4号商品的推荐值 = 0.32*3 + 0.252982*5 = 2.22491.如下图:
# coding:UTF-8
'''
Date:20160928
@author: zhaozhiyong
'''
import numpy as np
def load_data(file_path):
'''导入用户商品数据
input: file_path(string):用户商品数据存放的文件
output: data(mat):用户商品矩阵
'''
f = open(file_path)
data = []
for line in f.readlines():
lines = line.strip().split("\t")
tmp = []
for x in lines:
if x != "-":
tmp.append(float(x)) # 直接存储用户对商品的打分
else:
tmp.append(0)
data.append(tmp)
f.close()
return np.mat(data)
def cos_sim(x, y):
'''余弦相似性
input: x(mat):以行向量的形式存储,可以是用户或者商品
y(mat):以行向量的形式存储,可以是用户或者商品
output: x和y之间的余弦相似度
'''
numerator = x * y.T # x和y之间的额内积
denominator = np.sqrt(x * x.T) * np.sqrt(y * y.T)
return (numerator / denominator)[0, 0]
def similarity(data):
'''计算矩阵中任意两行之间的相似度
input: data(mat):任意矩阵
output: w(mat):任意两行之间的相似度
'''
m = np.shape(data)[0] # 用户的数量
# 初始化相似度矩阵
w = np.mat(np.zeros((m, m)))
for i in range(m):
for j in range(i, m):
if j != i:
# 计算任意两行之间的相似度
w[i, j] = cos_sim(data[i, ], data[j, ])
w[j, i] = w[i, j]
else:
w[i, j] = 0
return w
def user_based_recommend(data, w, user):
'''基于用户相似性为用户user推荐商品
input: data(mat):用户商品矩阵
w(mat):用户之间的相似度
user(int):用户的编号
output: predict(list):推荐列表
'''
m, n = np.shape(data)
interaction = data[user, ] # 用户user与商品信息
# 1、找到用户user没有互动过的商品
not_inter = []
for i in range(n):
if interaction[0, i] == 0: # 没有互动的商品
not_inter.append(i)
# 2、对没有互动过的商品进行预测
predict = {}
for x in not_inter:
item = np.copy(data[:, x]) # 找到所有用户对商品x的互动信息
for i in range(m): # 对每一个用户
if item[i, 0] != 0: # 若该用户对商品x有过互动
if x not in predict:
predict[x] = w[user, i] * item[i, 0]
else:
predict[x] = predict[x] + w[user, i] * item[i, 0]
# 3、按照预测的大小从大到小排序
return sorted(predict.items(), key=lambda d:d[1], reverse=True)
def top_k(predict, k):
'''为用户推荐前k个商品
input: predict(list):排好序的商品列表
k(int):推荐的商品个数
output: top_recom(list):top_k个商品
'''
top_recom = []
len_result = len(predict)
if k >= len_result:
top_recom = predict
else:
for i in range(k):
top_recom.append(predict[i])
return top_recom
if __name__ == "__main__":
# 1、导入用户商品数据
print ("------------ 1. load data ------------")
data = load_data("data.txt")
# 2、计算用户之间的相似性
print ("------------ 2. calculate similarity between users -------------")
w = similarity(data)
# 3、利用用户之间的相似性进行推荐
print ("------------ 3. predict ------------")
predict = user_based_recommend(data, w, 0)
# 4、进行Top-K推荐
print ("------------ 4. top_k recommendation ------------")
top_recom = top_k(predict, 2)
print (top_recom)