基于图的推荐算法及python实现
2017-12-27 18:27
886 查看
概述
基于图的模型(graph-based model)是推荐系统中的重要内容。在推荐系统中,用户行为数据可以表示成图的形式,具体地,可以用二元组(u,i)(u,i)表示,其中每个二元组(u,i)(u,i)表示用户uu对物品ii的产生过行为,这种数据很容易用一个二分图表示
其中users集 U={A,B,C}U={A,B,C}, items集I={a,b,c,d}I={a,b,c,d}。我们用G(V,E)G(V,E)来表示上图。V=U⋃IV=U⋃I,图中的边则是由数据集中的二元组确定。本文不考虑各边的权重(uu对ii的兴趣度),都默认为1。
与pagerank算法的区别
有了图之后我们要对u进行推荐物品,就转化为计算用户顶点u和与所有物品顶点之间的相关性,按照相关性的高低生成推荐列表。说白了,这是一个图上的排名问题,我们最容易想到的就是Google的pageRank算法。这里只给出迭代公式,Pagerank算法的具体细节在此不做赘述,具体的可以看http://blog.csdn.net/john_xyz/article/details/78915097。PR(i)=1−αn+α∑j∈(i)PR(j)out(j)PR(i)=1−αn+α∑j∈(i)PR(j)out(j)
上式中PR(i)PR(i)是网页i的访问概率(也就是重要度),αα是用户继续访问网页的概率,nn是网页总数。in(i)in(i)表示指向网页i的网页集合,out(j)out(j)表示网页j指向的网页集合。
与PageRank随机选择一个点开始游走(也就是说从每个点开始的概率都是相同的)不同,如果我们要计算所有节点相对于用户uu的相关度,则PersonalRank从用户uu对应的节点开始游走,每到一个节点都以1−α1−α的概率停止游走并从uu重新开始,或者以αα的概率继续游走,从当前节点指向的节点中按照均匀分布随机选择一个节点往下游走。这样经过很多轮游走之后,每个顶点被访问到的概率也会收敛趋于稳定,这个时候我们就可以用概率来进行排名了。
在执行算法之前,我们需要初始化每个节点的初始概率值。如果我们对用户uu进行推荐,则令uu对应的节点的初始访问概率为1,其他节点的初始访问概率为0,然后再使用迭代公式计算。而对于pageRank来说,由于每个节点的初始访问概率相同,所以所有节点的初始访问概率都是1/n1/n (nn是节点总数)。
Python代码实现
分别用两种方式实现PersonalRank算法,一种是用纯粹的for循环去做,另外一种是用矩阵乘法。对于大规模稀疏矩阵MM,使用稀疏矩阵乘法相比于for循环,能提高上百倍的效率。当然,如果对于大规模数据使用稠密矩阵,依然很慢。# coding:utf-8 import numpy as np import time import scipy.sparse as sparse import pandas as pd def PersonalRank(G, alpha, root): """ Random walk algorithm:calculate importance of all nodes in respect to the start_node :param G: graph :param alpha: probability of random walkRa :param root: start node of random walk :param num_iter: nums of iteration :return: type of dict, ex. {node1:prob1, node2:prob2,...} """ rank = dict() rank = {x:0 for x in G.keys()} rank[root] = 1 pre = np.zeros(n) # iteration while np.sum(abs(np.array(list(pre)) - np.array(list(rank.values())))) > 0.001: # initialize pre = rank.values() tmp = {x:0 for x in G.keys()} # 取节点i和它的出边尾节点集合ri for i, ri in G.items(): for j in ri: try: tmp[j] += alpha * rank[i] / (1.0 * len(ri)) except: continue tmp[root] += (1 - alpha) rank = tmp result = sorted(rank.items(), key=lambda x:x[1], reverse=True)[:num_candidates] return result def PersonalRankInMatrix(M, alpha, root): """ Personal Rank in matrix formation :param M: transfer probability matrix :param index2node: index2node dictionary :param node2index: node2index dictionary :return:type of list of tuple, ex. [(node1, prob1),(node2, prob2),...] """ result = dict() v = np.zeros(n) v[node2index[root]] = 1 v0 = v while np.sum(abs(v - (alpha*M.dot(v) + (1-alpha)*v0))) > 0.001: v = alpha * M.dot(v) + (1-alpha)*v0 for ind, prob in enumerate(v): result[index2node[ind]] = prob result = sorted(result.items(), key=lambda x:x[1], reverse=True)[:num_candidates] return result def Generate_Transfer_Matrix(G): """generate transfer matrix given graph""" index2node = dict() node2index = dict() for index,node in enumerate(G.keys()): node2index[node] = index index2node[index] = node # num of nodes n = len(node2index) # generate Transfer probability matrix, shape of (n,n) M = np.zeros([n,n]) for node1 in G.keys(): for node2 in G[node1]: # FIXME: some nodes not in the Graphs.keys, may incur some errors try: M[node2index[node2],node2index[node1]] = 1/len(G[node1]) except: continue return M, node2index, index2node def Generate_Transfer_SparseMatrix(G): """ generate transfer sparse matrix given graph :param G: graph, type of dict :return: transfer matrix, type of 'scipy.sparse.coo.coo_matrix' """ index2node = dict() node2index = dict() for index,node in enumerate(G.keys()): node2index[node] = index index2node[index] = node # num of nodes n = len(node2index) # initialize rows and columns rows = [] columns = [] data = [] # generate Transfer probability Sparse matrix, shape of (n,n) for node1 in G.keys(): for node2 in G[node1]: # FIXME: some nodes not in the Graphs.keys, may incur some errors try: rows.append(node2index[node2]) columns.append(node2index[node1]) data.append(1/len(G[node1])) except: continue rows = np.array(rows) columns = np.array(columns) data = np.array(data) M = sparse.coo_matrix((data, (rows,columns)),shape=(n,n)) return M, node2index, index2node # test algorithm performance if __name__ == '__main__': alpha = 0.85 root = 'A' num_iter = 100 num_candidates = 10 G = {'A' : {'a' : 1, 'c' : 1}, 'B' : {'a' : 1, 'b' : 1, 'c':1, 'd':1}, 'C' : {'c' : 1, 'd' : 1}, 'a' : {'A' : 1, 'B' : 1}, 'b' : {'B' : 1}, 'c' : {'A' : 1, 'B' : 1, 'C':1}, 'd' : {'B' : 1, 'C' : 1}} M, node2index, index2node = Generate_Transfer_SparseMatrix(G) n = len(M) print(pd.DataFrame(M, index=G.keys(), columns=G.keys())) time1 = time.time() result1 = PersonalRank(G, alpha, root) time2 = time.time() result2 = PersonalRankInMatrix(M, alpha, root) time3 = time.time() print(result1) print(result2) print(time2 - time1, time3 - time2)
关于稀疏矩阵的思考
在python中,可以借助官方库scipy.sparse和numpy中的dot和实现稀疏矩阵和稠密矩阵的相乘,具体如下import numpy as np import scipy.sparse as sparse r=np.array([0,3,1,2,6,3,6,3,4]) c=np.array([0,0,2,2,2,4,5,6,3]) data=np.array([1,1,1,1,1,1,1,1,1]) a = np.ones(7) sparse_matrix =sparse.coo_matrix((data, (r,c)), shape=(7,7)) print(sparse_matrix) print(sparse_matrix.todense()) M = sparse_matrix.dot(a) print(M)
reference
http://blog.csdn.net/gamer_gyt/article/details/51694250http://blog.csdn.net/harryhuang1990/article/details/10048383
相关文章推荐
- 基于用户协同过滤的推荐系统算法,python 实现
- 笔记︱基于网络节点的node2vec、论文、算法python实现
- 基于小波变换的多聚焦图像融合算法——Python实现
- 基于python快速实现排列组合算法
- python实现基于向量算法的的路由协议(RIP)
- 基于随机游走的社团划分算法label progation 的python实现
- python实现的推荐算法
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
- 《机器学习实战》基于朴素贝叶斯分类算法构建文本分类器的Python实现
- 排序算法(三)冒泡、选择排序的Python实现及算法优化详解 推荐
- 【机器学习算法实现】kNN算法__手写识别——基于Python和NumPy函数库
- 用于推荐系统的SVD算法python实现
- 基于python的分词算法的实现(1) - 算法
- 基于Levenberg-Marquardt训练算法的BP网络Python实现
- 基于Levenberg-Marquardt训练算法的BP网络Python实现
- 【笔记4】用pandas实现条目数据格式的推荐算法 (基于用户的协同)
- 基于随机游走的社团划分算法label progation 的python实现
- Python 基于语句检测和语句频谱分析实现文本汇总算法 (document summary algorithm)
- 基于评分数据的推荐算法实现:slopeone和矩阵分解
- 利用Python实现基于PCA算法的人脸识别