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

Chr*_*now 8 apache-spark apache-spark-ml apache-spark-mllib

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

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

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

即,如果您的用户潜在矩阵是 u 并且您的产品潜在矩阵是 v,对于模型中的用户 i,您可以通过执行以下操作获得分数: u_i * v 对于新用户,您没有潜在表示,因此请使用完整表示 full_u 并执行: 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
Run Code Online (Sandbox Code Playgroud)

这将返回:

[
  (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]))
]
Run Code Online (Sandbox Code Playgroud)

我也可以做类似的事情来获得 v 矩阵:

matrix_v = model.productFeatures()

print(matrix_v.take(2)) # take a look at the dataset
Run Code Online (Sandbox Code Playgroud)

这导致:

[
  (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]))
]
Run Code Online (Sandbox Code Playgroud)

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

yoh*_*lej 5

这个新用户不是矩阵 U,因此您在“k”因子中没有其潜在表示,您只知道其完整表示,即其所有评级。full_u 这里表示密集格式的所有新用户评分(不是稀疏格式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()))
Run Code Online (Sandbox Code Playgroud)

那么这只是一个乘法的问题: full_u*Vt*Vt.T

VtV与其他答案相比进行了调换,但这只是惯例问题。

请注意,该Vt*Vt.T产品是固定的,因此如果您打算将其用于多个新用户,则预先计算它在计算上会更有效。实际上,对于多个用户来说,最好将他们的所有评分放入 bigU(与我的一个新用户示例的格式相同),然后进行矩阵乘积: bigU*Vt*Vt.T获取所有新用户的所有评分。可能仍然值得检查产品是否以最有效的方式完成操作数量。