推荐算法学习实践:基于物品相似度
Posted python与人工智能学习交流
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了推荐算法学习实践:基于物品相似度相关的知识,希望对你有一定的参考价值。
推荐算法学习实践(一):基于物品相似度
明觉
最近在和推荐系统打交道,学习实践过程中有一些细节、这里记录一下,与大家共同学习和分享交流,不足之处,欢迎大家指正交流。
在物品数量远小于用户数量的推荐场景中,会选择基于物品相似度的推荐算法。比如用户在亿级,物品在万级,符合基于物品相似度的场景。如果用户在亿级,在计算物品相似度时依然计算量巨大,这里采用奇异值分解来降维提取特征。
首先,导入数据,程序输入的数据格式为,用户ID、物品ID、一段时间内的购买频次三列。用户ID、物品ID提前在数据库中处理为0~m-1,0~n-1,m为用户数,n为商品数。
import pandas as pd
df = pd.read_table("data.txt", header=-1, sep=",")
这三列数据如果转成矩阵,是一个巨大的稀疏矩阵,在sklearn中稀疏矩阵和奇异值分解,使用 sklearn.decomposition.TruncatedSVD(),而具体文件其中的参数说明如下:
algorithm : string, default = "randomized"
SVD solver to use. Either "arpack" for the ARPACK wrapper in SciPy
(scipy.sparse.linalg.svds), or "randomized" for the randomized
algorithm due to Halko (2009).
这里直接用 scipy.sparse.linalg.svds,可以分解为有限个奇异值和对应的奇异向量.这里有一个问题,既然没有完全分解,怎么判断前K个奇异值的贡献占所有奇异值贡献的比例?其实所有奇异值的总贡献,也就是平方和,等于矩阵的转置乘以矩阵得到的矩阵对角线元素之和,其实就是矩阵本身所有元素的平方和。对应到三列数据,就是第三列数据的平方和。
接下来按照稀疏矩阵的 scipy.sparse.csr_matrix 的格式要求处理一下数据,并进行奇异值分解。
from scipy.sparse.linalg import svds
from scipy.sparse import csr_matrix
X = csr_matrix((df[2]+0.0001, (df[0], df[1]))) # 这里加上0.0001是因为,svds分解时只接受float和double型数字
U,Sigma,VT = svds(X, SigmaN) # SigmaN 为奇异值个数
VT 为 K*N的矩阵,K为奇异值个数,N为物品个数,接下来计算物品相似度矩阵,对角线为1的对称矩阵。由于物品个数有限,这里直接利用numpy矩阵计算方法来计算物品两两之间的相似度。在内存够用的情况下,矩阵计算比我自己写的循环快的多多多。。。
def cosSim(VT):
r, c = VT.shape
VTnorm = np.array(np.sqrt(np.mat(VT*VT).T*np.mat([1]*r).T))
VTm = np.mat(VT)
VTV = VTm.T*VTm
cosSim = 0.5 + 0.5*np.array(VTV)/VTnorm/VTnorm.T
return np.mat(cosSim)
最后,使用相似度矩阵计算用户对每个商品之间可能购买频次,返回每个用户的推荐商品topN。
def recommend(X,sim,u,N):
return np.argsort(np.array(X[u,:]*Sim)/np.sum(Sim, 1).T)[:, -1:-(1+N):-1]
由于用户数量巨大,可以分批计算结果并输出
output = open('user_result.txt', 'w')
l = step(X.shape[1], len(user_valid))
for i in range(len(l)-1):
print(l[i], l[i+1])
Y = recommend(X, Sim, user_valid[l[i]:l[i+1]], itemN).tolist()
for u, y in zip(user_valid[l[i]:l[i+1]], Y):
output.write(str(u))
output.write(":")
line = [str(s) for s in y]
output.write(",".join(line)+ "\n")
output.close()
其中step函数如下:
def step(item_num, user_num):
step = int(1e8/item_num)
l = [k for k in range(0, user_num, step)]
return l + [user_num]
#########################################################################
完整代码,如下:
import numpy as np
import pandas as pd
from scipy.sparse.linalg import svds
from scipy.sparse import csr_matrix
import datetime
import time
SigmaN = 10
itemN = 5
testSize = 1e8
def timer(func):
def wrapper(*arg, **kw):
t0 = time.time()
print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), func.__name__, 'start......')
result = func(*arg, **kw)
t1 = time.time()
print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), func.__name__, 'finished, spent time:', round(t1-t0, 2), 's.')
return result
return wrapper
@timer
def cosSim(VT):
r, c = VT.shape
VTnorm = np.array(np.sqrt(np.mat(VT*VT).T*np.mat([1]*r).T))
VTm = np.mat(VT)
VTV = VTm.T*VTm
cosSim = 0.5 + 0.5*np.array(VTV)/VTnorm/VTnorm.T
return np.mat(cosSim)
@timer
def recommend(X,sim,u,N):
return np.argsort(np.array(X[u,:]*Sim)/np.sum(Sim, 1).T)[:, -1:-(1+N):-1]
@timer
def step(item_num, user_num):
step = int(testSize/item_num)
l = [k for k in range(0, user_num, step)]
return l + [user_num]
df = pd.read_table("data.txt", header=-1, sep=",")
df_valid = pd.read_table("user.txt", header=-1, sep=",")
output = open('user_result.txt', 'w')
user_valid = df_valid[0]
X = csr_matrix((df[2]+0.0001, (df[0], df[1])))
del df
U,Sigma,VT = svds(X, SigmaN)
del U, Sigma
Sim = cosSim(VT)
l = step(X.shape[1], len(user_valid))
for i in range(len(l)-1):
print(l[i], l[i+1])
Y = recommend(X, Sim, user_valid[l[i]:l[i+1]], itemN).tolist()
for u, y in zip(user_valid[l[i]:l[i+1]], Y):
output.write(str(u))
output.write(":")
line = [str(s) for s in y]
output.write(",".join(line)+ "\n")
output.close()
以上是关于推荐算法学习实践:基于物品相似度的主要内容,如果未能解决你的问题,请参考以下文章