mahout算法源码分析之Collaborative Filtering with ALS-WR (三)parallelALS initializeM和for循环
Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit。
接上篇,此篇分析parallelALS的initializeM函数和for循环(for循环里面含有一个QR分解,此篇只分析到这里为止)。parallelALS的源码对应为:org.apache.mahout.cf.taste.hadoop.als.ParallelALSFactorizationJob,首先来总结一下,前篇blog已有的内容:
PathToUserRatings: <key,vlaue> --> <userID,[ItemID:rating,ItemID:rating,...];
PathToItemRatings: <key,vlaue> --> <itemID,[userID:rating,userID:rating,...];
PathToAverageRatings: <key,value> --> <0,[itemID:averageRating,itemID:averageRating,...]>
打开initializeM函数可以看到下面的源码:
这里方框中可以看到有3692个item,和前面分析一致,同时每个都含有20个值,从0到19,这个把值往后面拉就可以看到了。在map函数中,有两个变量值得注意,其一是ratings,这个变量就是pathToUserRatings的value,即[ItemID:rating,ItemID,rating,...]这里的ratings都是真实的用户对于item的评价。其二是featureVectors,这个是通过下面的方式转换得到的:
首先由userID所有评价过的item找出在UorM中存在的项,然后把这些项全部赋值给featureVector,即可得到userID的featureVector了。然后,然后,然后重点来了:Vector uiOrmj = solver.solve(featureVectors, ratings, lambda, numFeatures);不管三七二十几,先打开solve函数来看看:
其中第一行全部是相应item的平均评价值,下面的行则是随机数评价值。然后到了Matrix RiIiMaybeTransposed = createRiIiMaybeTransposed(ratingVector);这里的RiIiMaybeTransposed 变量是把ratings进行转置:
接下来到了Matrix Ai = addLambdaTimesNuiTimesE(MiIi.times(MiIi.transpose()), lambda, nui);即Ai的值其实是等于MiIi的转置乘以MiIi,这里的乘法是矩阵的乘法。比如行矩阵[a1,a2,a3]乘以列矩阵[b1;b2;b3],那么即是1*3的行矩阵乘以3*1的列矩阵,得到1*1的矩阵:a1*b1+a2*b2+a3*b3。通俗来说应该是M*R的矩阵乘以R*N的矩阵,然后得到M*N的矩阵。Mili.transpose()函数就是求Mili的转置,times是求两个矩阵相乘。addLambdaTimesNuiTimesE方法后面的两个参数的使用是在MiIi矩阵转置相乘后把对角线(row=col)的值更新为原始值+lambda*nui即可。那么Vi就相对来说比较简单了:Matrix Vi = MiIi.times(RiIiMaybeTransposed); 即是Mili和RiIiMaybeTransposed的矩阵乘积了。
最后到了solve函数,这个函数返回为:
Vector solve(Matrix Ai, Matrix Vi) { return new QRDecomposition(Ai).solve(Vi).viewColumn(0); }额,好吧,居然是QR分解,我晕,本来基本的数学还ok,这样居然用到了QR分解,我去,看了半个钟头,感觉好复杂了。。。
分享,成长,快乐
转载请注明blog地址:http://blog.csdn.net/fansy1990