基于简单的协同过滤和网状推荐系统的实现(python和moviellens数据集)

  本文的理论基础是上篇我看的《个性化推荐系统的研究进展》(周涛等,2009),这是一篇计较老的综述了,所以里面的方法也比较老:),但是练手不错,最起码实现没那么头疼,主要是电脑能相对的运算xD。原理在我的另一个思维导图里已经有了,在此不再赘述,直接上代码:(本代码力求实现,所以还没有优化,目前采用串行计算,有时间的话会优化):

  结果:

  a.推荐数为100时,基于网络结构的r因子为0.4左右,实际上是非常大的,但是不是说明模型的效果不是特别好,因为:;

    (1):我将用户的度或者电影的度为零时依然参与了构建,冷启动拉低了效率

    (2):度大的用户或者电影的影响力过于巨大;

    (3):与协同过滤一样的问题,关联矩阵稀疏

  b..按照我的误差函数,最后协同过滤结果为-2.6,也就是说推荐系统推测出来的评分值与用户本身评分差距平均值为2.8分(满分5分),误差看来很大,实则因为:

    (1):存在孤立点,或者说是新用户、新电影,这种冷启动是协同过滤无法处理的;

    (2):关联矩阵十分稀疏,而且数据集中的打分多是4、5分,在拉低后差距愈发明显。

  0,提示:

  (1)虽然没有用并行算法,但是可以考虑用jit加速。

  (2)而且很重要的一点是,关联矩阵非常稀疏,要考虑度为零,相似性为零等情况,不然老会得不到结果。

  (3)本实例中用的是6040x3952(用户,电影)的数据包。

  (4)基于网络模型采用综述里的评价指标,协同过滤我用的是推荐打分值与原有打分值的差值平均值(原来没有打分的差值为0)

  1,用户与产品的关联矩阵、度、评分矩阵的写入:

def GetData():
    user_vec = np.zeros((6040,3952))
    user_rating = np.zeros((6040,3952))
    degree_user = np.zeros((1,6040))
    degree_mov = np.zeros((1,3952))

    rating = np.loadtxt("rating.txt",dtype = np.str,delimiter= "::")
    #print(rating[:2,:3])
    data = np.array(rating[0:,:3],dtype=np.int)


    #写入用户向量和用户、电影的度
    for i in range(0,1000209):
        if data[i][2] > 3:
            user_vec[int(data[i][0])-1][int(data[i][1])-1] = 1
            degree_user[0][data[i][0] - 1] = int(degree_user[0][data[i][0] - 1] +1)
            degree_mov[0][data[i][1] - 1] = int(degree_mov[0][data[i][1] - 1] + 1)
        if data[i][2]:
            user_rating[int(data[i][0]) - 1][int(data[i][1]) - 1] = int(data[i][2])
    return user_vec,user_rating,degree_user,degree_mov

  2,相似度计算:

def SimCom(user_vec):
    #相似度矩阵
    user_sim = np.zeros((6040, 6040))
    for i in range(0,6040):
        for j in range(i+1,6039):
            user_sim[i][j] = float(np.dot(user_vec[i], user_vec[j]) / (np.linalg.norm(user_vec[i]) * np.linalg.norm(user_vec[i])))
            user_sim[i][j] = round(user_sim[i][j],3)
        user_sim[i][i] = 1
        if i %10 ==0 :
            print(i)

    for i in range(1,6040):
        for j in range(0,i):
            user_sim[i][j] =user_sim[j][i]
    return user_sim

 

  3,新的评分矩阵生成:

#新的评分矩阵
'''
在此不考虑新打分矩阵出现后需要迭代运算
'''
@jit
def RecS_rating(user_sim,user_rating,user_vec):
    user_NewRating = np.zeros((6040,3952))
    for i in range(0,6040):
        all_sim = np.sum(user_sim[i])
        degree = np.sum(user_vec[i])
        if degree != 0:
            rating_avg= np.sum(user_rating[i]) / degree
        else:
            rating_avg= 0
        for j in range(0,3952):
            for k in range(0,6040):
                user_NewRating[i][j] = user_NewRating[i][j] + user_sim[i][j] * (user_rating[k][j]-user_rating[i][j])
            if all_sim != 0:
                user_NewRating[i][j] =int(user_NewRating[i][j]/all_sim+ rating_avg)
            else:
                user_NewRating [i][j] = 5
            if user_NewRating[i][j] > 5:
                user_NewRating[i][j] = 5
            if user_NewRating[i][j] <0:
                user_NewRating[i][j] = 0
                # 显示计算到哪
        if i % 100 == 0:
            print(i)
    return  user_NewRating

 

  4,资源分配矩阵生成:

#资源配额矩阵
def Wight_mov(degree_user,degree_mov,user_vec):
    w_mov = np.zeros((3952, 3952))
    for i in range(0,3952):
        for j in range(0,3952):
            w_mov[i][j] = 0
            for k in range(0,6040):
                if degree_user[0][k] == 0:
                    continue
                w_mov[i][j] = w_mov[i][j] + (user_vec[k][i]*user_vec[k][j])/degree_user[0][k]
            if degree_mov[0][j] == 0:
                w_mov[i][j] = 0
                continue
            w_mov[i][j] = round(w_mov[i][j] / degree_mov[0][j],4)
            #print(j)
        #显示计算到哪
        if i %100 ==0 :
            print(i)
    return w_mov

 

  5,Top-K(用于选择推荐值或者评分最高的K个值)矩阵:


#top-K排序
def partition_arg_topK(matrix1, K):
    matrix = 1.- matrix1
    a_part = np.argpartition(matrix, K, axis=1)
    column_index = np.arange(matrix.shape[0])[:, None]
    a_sec_argsort_K = np.argsort(matrix[column_index, a_part[:, 0:K]], axis=1)
    return a_part[:, 0:K][column_index, a_sec_argsort_K]

 

  6,输出参数(以协同过滤为例子:评判标准定为用户已选产品新老评分之差,再取平均)而网状则不同,方法详见另一个思维导图:

   6.1 协同过滤

def Result_corr(user_vec,user_rating,new_rating):
correct_corr = np.zeros((1,6040))
sum_valid = 0
for i in range(0,6040):
degree = np.sum(user_vec[i])
for k in range(0, 3952):
if user_vec[i][k] == 1:
correct_corr[0][i] =correct_corr[0][i]+ (new_rating[i][k] - user_rating[i][k])
if degree != 0:
correct_corr[0][i] = correct_corr[0][i] / degree
sum_valid = sum_valid+1
else:
correct_corr[0][i]= 0
#print(degree)
#print(sum_valid)
#print(np.sum(correct_corr) / sum_valid)
return correct_corr

   6.2基于网络

def Result_net(topK,user_vec):
    correct_net= np.zeros(6040)
    for i in range(0,6040):
        find_in = 0
        for k in range(0,3952):
            #计算推荐指数
            for j in range(0,50):
                if user_vec[i][k] == 1 and (k in topK[i]) and topK[i][j] == k:
                     correct_net[i] = correct_net[i]+((j+1)/50)
                     find_in = find_in + 1
                     break
        if find_in !=0:
            correct_net[i] = round(correct_net[i] / find_in,3)
        else:
            correct_net[i] = 1
        print(i)
    return correct_net

  7,一些中间数据结果:

资源分配矩阵:

 

     算了,数据多,不在此展示了:)

posted @ 2020-03-07 11:35  无极183  阅读(383)  评论(0编辑  收藏  举报
/*
*/