ALS模型 - 如何生成full_u * v ^ t * v?

时间:2017-01-08 20:23:37

标签: apache-spark apache-spark-mllib apache-spark-ml

我正在试图弄清楚ALS模型如何在批处理更新之间预测新用户的值。在我的搜索中,我遇到了这个stackoverflow answer。为了方便读者,我复制了以下答案:

  

您可以使用经过培训的模型获得新用户的预测(无需更新):

     

要获得模型中用户的预测,可以使用其潜在表示(大小为f(因子数)的向量u),乘以产品潜在因子矩阵(由所有产品的潜在表示构成的矩阵) ,一堆大小为f)的向量,并为您提供每个产品的分数。对于新用户,问题在于您无法访问其潜在表示(您只能获得大小为M(不同产品数量)的完整表示,但您可以使用相似度函数来计算类似的潜在表示通过乘以产品矩阵的转置,为这个新用户提供表示。

     

即。如果您的用户潜在矩阵是您且您的产品潜在矩阵是v,对于模型中的用户i,您可以通过执行以下操作获得分数:u_i * v对于新用户,您没有潜在的表示,因此请完整表示full_u和do:full_u * v ^ t * v这将接近新用户的潜在因素,并应提供合理的建议(如果模型已经为现有用户提供了合理的建议)

     

要回答培训问题,这可以让您为新用户计算预测,而无需对模型进行繁重的计算,现在您只需要进行一次。因此,您可以在晚上进行批处理,并且仍然可以在白天对新用户进行预测。

     

注意:MLLIB允许您访问矩阵u和v

上面引用的文字是一个很好的答案,但是,我很难理解如何以编程方式实现此解决方案。例如,矩阵u和v可以通过以下方式获得:

# pyspark example

# ommitted for brevity ... loading movielens 1M ratings

model = ALS.train(ratings, rank, numIterations, lambdaParam)

matrix_u = model.userFeatures()

print(matrix_u.take(2)) # take a look at the dataset

返回:

[
  (2, array('d', [0.26341307163238525, 0.1650490164756775, 0.118405282497406, -0.5976635217666626, -0.3913084864616394, -0.1379186064004898, -0.3866392970085144, -0.1768060326576233, -0.38342711329460144, 0.48550787568092346, -0.18867433071136475, -0.02757863700389862, 0.1410026103258133, 0.11498363316059113, 0.03958914801478386, 0.034536730498075485, 0.08427099883556366, 0.46969038248062134, -0.8230801224708557, -0.15124185383319855, 0.2566414773464203, 0.04326820373535156, 0.19077207148075104, 0.025207923725247383, -0.02030213735997677, 0.1696728765964508, 0.5714617967605591, -0.03885050490498543, -0.09797532111406326, 0.29186877608299255, -0.12768596410751343, -0.1582849770784378, 0.01933656632900238, -0.09131495654582977, 0.26577943563461304, -0.4543033838272095, -0.11789630353450775, 0.05775507912039757, 0.2891307771205902, -0.2147761881351471, -0.011787488125264645, 0.49508437514305115, 0.5610293745994568, 0.228189617395401, 0.624510645866394, -0.009683617390692234, -0.050237834453582764, -0.07940001785755157, 0.4686132073402405, -0.02288617007434368])), 
  (4, array('d', [-0.001666820957325399, -0.12487432360649109, 0.1252429485321045, -0.794727087020874, -0.3804478347301483, -0.04577340930700302, -0.42346617579460144, -0.27448347210884094, -0.25846347212791443, 0.5107921957969666, 0.04229479655623436, -0.10212298482656479, -0.13407345116138458, -0.2059325873851776, 0.12777331471443176, -0.318756639957428, 0.129398375749588, 0.4351944327354431, -0.9031049013137817, -0.29211774468421936, -0.02933369390666485, 0.023618215695023537, 0.10542935132980347, -0.22032295167446136, -0.1861676126718521, 0.13154461979866028, 0.6130356192588806, -0.10089754313230515, 0.13624103367328644, 0.22037173807621002, -0.2966669499874115, -0.34058427810668945, 0.37738317251205444, -0.3755438029766083, -0.2408779263496399, -0.35355791449546814, 0.05752146989107132, -0.15478627383708954, 0.3418906629085541, -0.6939512491226196, 0.4279302656650543, 0.4875738322734833, 0.5659542083740234, 0.1479463279247284, 0.5280753970146179, -0.24357643723487854, 0.14329688251018524, -0.2137598991394043, 0.011986476369202137, -0.015219110995531082]))
]

我也可以做类似的获取v矩阵:

matrix_v = model.productFeatures()

print(matrix_v.take(2)) # take a look at the dataset

这导致:

[
  (2, array('d', [0.019985994324088097, 0.0673416256904602, -0.05697149783372879, -0.5434763431549072, -0.40705952048301697, -0.18632276356220245, -0.30776089429855347, -0.13178342580795288, -0.27466219663619995, 0.4183739423751831, -0.24422742426395416, -0.24130797386169434, 0.24116989970207214, 0.06833088397979736, -0.01750543899834156, 0.03404173627495766, 0.04333991929888725, 0.3577033281326294, -0.7044714689254761, 0.1438472419977188, 0.06652364134788513, -0.029888223856687546, -0.16717877984046936, 0.1027146726846695, -0.12836599349975586, 0.10197233408689499, 0.5053384900093079, 0.019304445013403893, -0.21254844963550568, 0.2705852687358856, -0.04169371724128723, -0.24098040163516998, -0.0683765709400177, -0.09532768279314041, 0.1006036177277565, -0.08682398498058319, -0.13584329187870026, -0.001340558985248208, 0.20587041974067688, -0.14007550477981567, -0.1831497997045517, 0.5021498203277588, 0.3049483597278595, 0.11236990243196487, 0.15783801674842834, -0.044139936566352844, -0.14372406899929047, 0.058535050600767136, 0.3777201473712921, -0.045475270599126816])), 
  (4, array('d', [0.10334215313196182, 0.1881643384695053, 0.09297363460063934, -0.457258403301239, -0.5272660255432129, -0.0989445373415947, -0.2053477019071579, -0.1644461452960968, -0.3771175146102905, 0.21405018866062164, -0.18553146719932556, 0.011830524541437626, 0.29562288522720337, 0.07959598302841187, -0.035378433763980865, -0.11786794662475586, -0.11603366583585739, 0.3776192367076874, -0.5124108791351318, 0.03971947357058525, -0.03365595266222954, 0.023278912529349327, 0.17436474561691284, -0.06317273527383804, 0.05118614062666893, 0.4375131130218506, 0.3281322419643402, 0.036590900272130966, -0.3759073317050934, 0.22429685294628143, -0.0728025734424591, -0.10945595055818558, 0.0728464275598526, 0.014129920862615108, -0.10701996833086014, -0.2496117204427719, -0.09409723430871964, -0.11898282915353775, 0.18940524756908417, -0.3211393356323242, -0.035668935626745224, 0.41765937209129333, 0.2636736035346985, -0.01290816068649292, 0.2824321389198303, 0.021533429622650146, -0.08053319901227951, 0.11117415875196457, 0.22975310683250427, 0.06993964314460754]))
]

但是,我不确定如何从此进展到full_u * v^t * v

2 个答案:

答案 0 :(得分:4)

这个新用户不是矩阵U,所以你没有'k'因子的潜在表示,你只知道它的完整表示,即它的所有评级。 full_u here表示密集格式(不是稀疏格式ratings)的所有新用户评分,例如:

[0 2 0 0 0 1 0]如果用户u将项目2评为2,项目6评分为1。

那么你可以像你一样得到v并将它变成numpy中的矩阵,例如:

pf = model.productFeatures()
Vt = np.matrix(np.asarray(pf.values().collect()))

然后只是乘法的问题: full_u*Vt*Vt.T

与其他答案相比,

VtV被转置,但这只是一个惯例问题。

请注意,Vt*Vt.T产品是固定的,因此如果您要将其用于多个新用户,那么预先计算它将在计算上更有效。实际上对于多个用户而言,最好将所有评级放在bigU中(与我的一个新用户示例的格式相同)并且只做矩阵产品: bigU*Vt*Vt.T获取所有新用户的所有评分。可能还值得检查产品是否以最有效的方式完成操作。

答案 1 :(得分:2)

只是一句警告。人们谈论用户和产品矩阵,就像它们是左右奇异向量一样。但据我所知,用于查找U和V的方法是直线平方误差代价函数的优化,这不能保证SVD的正交性。

换句话说,以代数方式思考上述答案所声称的内容。我们有一个完整的评级矩阵R,n个用户对p个产品的n个p矩阵。我们用k个潜在因子对其进行分解以近似R = UV,其中U的行(n×k矩阵)是潜在的用户表示,V的列(p×p矩阵)是潜在的乘积表示。为了找到全新用户的矩阵R的潜在用户表示而不重新模型,我们需要:

       R = U V  
R V^{-1} = U V V^{-1}  
R V^{-1} = U I_{k}  
R V^{-1} = U  

其中I_ {k}是k维单位矩阵,并且V ^ { - 1}是V的右对角的p乘以上。上面的提示假设V ^ {T} = V ^ { - 1}。这不保证。一般来说,不能保证假设这是真的,除了无意义的答案之外,你将得到任何答案。

如果我在MLLib的CF实现背后的优化方法中遗漏了一些东西,请告诉我。在ALS模型中是否有一个技巧可以保证我缺失的正交性?