转载注明出处长门yuki,本文代码见末尾github链接。
本文参考一下博客及代码仓库,感谢网上的这些分享者:
1.我了解到大致了原理:
数据挖掘(一):分类技术-二分网络上的链路预测(电影推荐)
2.对其中f矩阵算法改进:
数据挖掘-二分网络上的链路预测:兴趣推荐系统-电影推荐
3.ROC曲线原理说明:
无涯的回答
4.LaTex公式简单参考:
Latex数学公式编写
其中主要参考的详细实现,对于其中除零bug已经反馈BlackJocker1995/rating_analysis
一、实验要求
基于网络结构的链路预测算法被广泛的应用于信息推荐系统中。算法不考虑用户和产品的内容特征,把它们看成抽象的节点,利用用户对产品的选择关系构建二部图。为用户评估它从未关注过的产品,预测用户潜在的消费倾向。
简单的讲就通过现有数据集,通过二部图资源分配的算法来为用户推荐和数据集中用户看过后这部电影后联系度排名前几部的电影。
要求不多讲了,基本文档都是一样的。
二、简要分析
1.数据预处理
我们需要处理数据来预测,就得先分析数据的内容。
先来看数据集ml-1m,分别有movies.dat,ratings.dat,users.dat还有一份说明README,参考说明可知其中movies.dat包含序号,电影名,上映时间,电影类型,导演。Users,dat包含年龄性别职业等等,可见这两个数据集并不是我们所需要的。下面详细讲解rating.dat数据集。
调用head()函数先看ratings.dat数据前几行:(参见代码print1):
由上图可知ratings.dat包含了用户编号,电影编号,评级水平(1-5星),时间戳。显然我们可以根据此数据集构建二部图并计算资源分配矩阵。
2.二部图的构建
设立阈值threshold=3,假定该数据由m 个用户和n 个电影构成二部图,其中如果用户i对电影j的评分大于该阈值, 就在i 和j 之间连接一条边aji =1(i =1 ,2 , …, m ;j =1 , 2 , … , n), 否则aji =0。那么这个推荐系统可以用一个具有m +n 个节点的二部分图表示。
3.基于二部分图资源分配的推荐算法
如何计算资源配额矩阵呢?简单来说是求对看过一部电影的用户,来推荐数据中看过该电影的用户中都看过的电影中前几部电影。
算法如下:
对于任意目标用户i , 推荐算法的目的是把所有i 没有选择过的产品按照i 喜欢的程度进行排序, 并且把排名靠前的那些产品推荐给i .假设i 选择过的所有产品, 都具有某种向i 推荐其他产品的能力.这个抽象的能力可以看做位于相关产品上的某种可分的资源———拥有资源的产品会把更多的资源交给自己更青睐的产品.对于有m 个用户和n 个产品的一般的推荐系统, 如果用表示Wij 产品j 愿意分配给产品i 的资源配额, 可以得到Wij 的一般表达式:
w i j = 1 k j ∑ l = 1 m a i l a j l k l w_{i j}=\frac{1}{k_{j}} \sum\limits_{l=1}^{m} \frac{a_{i l} a_{j l}}{k_{l}} wij=kj1l=1∑mklailajl
对于上式:若直接按部就班地来计算将循环
m
∗
n
2
m*n^2
m∗n2次,而python中有矩阵相乘优化,所以难点在于如何将上式转化成矩阵形式。
4. 算法改进
这里就不详细介绍简单易推的东西了
对原矩阵A(
m
∗
n
m*n
m∗n),设其转置矩阵为B(
n
∗
m
n*m
n∗m)。
考虑
∑ l = 1 m a i l a j l = ∑ l = 1 m a i l b l j \sum\limits_{l=1}^{m} a_{i l} a_{j l}=\sum\limits_{l=1}^{m} a_{i l} b_{l j} l=1∑mailajl=l=1∑mailblj
即:
(
a
01
a
02
⋯
a
i
j
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
)
×
(
b
00
⋯
⋯
⋯
b
01
⋯
⋯
⋯
⋯
⋯
⋯
⋯
b
j
i
⋯
⋯
⋯
)
=
(
∑
a
b
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
⋯
)
\left( \begin{matrix} a_{01} & a_{02} & \cdots & a_{ij} \\ \cdots & \cdots & \cdots & \cdots \\ \cdots & \cdots & \cdots & \cdots \\ \cdots & \cdots & \cdots & \cdots \\ \end{matrix} \right) \times \left( \begin{matrix} b_{00} & \cdots & \cdots & \cdots \\ b_{01} & \cdots & \cdots & \cdots \\ \cdots & \cdots & \cdots & \cdots \\ b_{ji} & \cdots & \cdots & \cdots \\ \end{matrix} \right) = \left( \begin{matrix} \sum_{}^{}{ab} & \cdots & \cdots & \cdots \\ \cdots & \cdots & \cdots & \cdots \\ \cdots & \cdots & \cdots & \cdots \\ \cdots & \cdots & \cdots & \cdots \\ \end{matrix} \right)
⎝⎜⎜⎛a01⋯⋯⋯a02⋯⋯⋯⋯⋯⋯⋯aij⋯⋯⋯⎠⎟⎟⎞×⎝⎜⎜⎛b00b01⋯bji⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⎠⎟⎟⎞=⎝⎜⎜⎛∑ab⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⎠⎟⎟⎞
那么我们只需要将A矩阵与Kj矩阵和Kl矩阵分别按次序相除即可,最后在乘以原矩阵转置就符合矩阵运算法则。
先看从矩阵A按列方向逐个乘
a
i
l
k
l
\displaystyle\frac{a_{i l}}{k_{l}}
klail可以并行运算,按行方向乘,
a
j
l
k
j
\displaystyle\frac{a_{j l}}{k_{j}}
kjajl可以并行运算。以矩阵形式运算,公式变为:
W = ( ∑ j = 1 m ( ∑ i = 1 n ( A i / Y ) ) / K ) ∗ A T W=\left(\sum\limits_{j=1}^{m}\left(\sum\limits_{i=1}^{n}\left(A_{i} / Y\right)\right) / K\right) * A^{T} W=(j=1∑m(i=1∑n(Ai/Y))/K)∗AT
其中Y矩阵, Y i Y_i Yi表示每个用户i选择的电影度数,K矩阵, K j K_j Kj表示电影j一共被选择的次数。
1. for i in range (1,n,1):
2. temp[:,i]=A[:,i]/Y
3. for j in range (1,m,1):
4. temp2[j,:]=temp[j,:]/K
5. D=npy.dot(A.T,temp2)
用ptyhon可以写的更简单一点,我们再乘以其W原矩阵转置可以得到F,封装成函数:
def compute_f_mat(mat_rat,user_count,movie_count):
temp = (mat_rat / user_count.reshape([-1,1]) )/ movie_count.reshape([1,-1])
W = np.dot(mat_rat.T, temp)
f = np.dot(W, mat_rat.T).T
return f
5.输出结果并绘制ROC曲线
参考其他博客即可。
结果如下:
三、部分细节
源码见文末,其中需注意源码中有四个print注释掉了,皆为中间结果。
print Number格式如下:
'''
#print Number
code...
'''
想要恢复查看,删掉注释号即可。
print1:
打印ratings.dat数据的行数列数,以及前几行数据集
print2:
打印原数据集大小,以及训练集与测试集大小之比:
print3:
对比前后效果,原电影-用户推荐ratings图和建立好的二分网络:
print4:
打印用户数量和电影数量、F矩阵大小。
以及查看前4名用户对各个电影推荐f系数。
源码链接
链接:Vsingeryh/datamining-exp1
备注:包含所需数据集ml-1m、源码main.py,以及报告exp1.pdf。
具体见仓库README说明。