这个问题最初是我的作业,但我的回答是错误的,我很好奇这个问题的最佳解决方案是什么。
目标是使用4个map reduce步骤计算“Recommender System bootstrapping algorithm”的关键方面。我的问题是第3步,所以我只带来它的细节。
输入:表单记录:
1。 (人口数量,项目,数量 评级用户,评级总和,总和 评级平方)
2。 (人口 id,splitter item,likers / dislikers, 项目,评级用户数,总和 评级,平均等级总和)
第二种形式非常类似于第一种形式,但每种形式的记录(分裂者,喜欢者/不喜欢者) - 喜欢/不喜欢的人是布尔值。
这意味着(我认为)有2 ^ |项目|来自第一种形式的每条记录的秒形式的记录......(许多同学做错了(我认为......)假设有相同数量的第一和第二形式记录)
任务说明:
此步骤将根据分割器电影计算每部电影引起的平方误差(SE)。
提示:
假设存在一个字符串 先于(在系统的排序顺序中) 任何分配者电影id。
这必须在一个mapreduce步骤中完成!
其他背景:
这是在“The Netflix Challange”的背景下学到的。
SE定义:
编辑:有关问题的其他材料[关于netflix挑战的一些说明和有关问题的数学信息]可以在this link [特别是幻灯片12-24]中找到
EDIT2:请注意,由于我们正在使用map / reduce,因此我们无法假设任何有关ORDER记录的信息都将被处理[在map和reduce中]。
答案 0 :(得分:3)
我不确定我理解你的问题。
你最终想要的是SE(U)。在幻灯片23和24的一些数学细节之后,使用\ sum_ {i} SE(U)_i
计算“平凡”。你自己明白,第4个和最后一个是地图缩小以得到这个总和。
第三步是地图缩小到(LaTeX风格)
SE(U)_i = \sum_{u in U_i} (r_{u,i} - r_i)^2
在Python中,这可能如下所示:
def map(Ui):
''' Ui is the list of user who have rated the film i'''
for user in Ui:
results.append((user,(r_{u,i} - r_i)^2))
def reduce(results):
''' Returns a final pair (item, SE(U)_i ) '''
return (item, sum([value for user,value in results]))
修改:我的原始答案不完整。让我再次表达。
你最终想要的是每个分配器的SE(U)。
步骤准备一些有关商品的有用数据。发出的条目定义为:
key = (population_id, item)
value =
number: |U_i|,
sum_of_ratings: \sum_{u \ in U_i} r_{u,i}
sum_of_squared_ratings: \sum_{u \in U_i} r_{u,i} ^2
现在,对于任何给定的分割片M:
U_M = U_{+M} + U_{-M} + U_{M?}
步骤b 为每个分割器M明确计算小子群M +和M-的统计量。
NB赞成者/不喜欢者不是布尔本身,它是子群体识别者'+'或' - '
每个拆分项有2个新条目:
key = (population_id, item, M, '+')
value =
number: |U_i(+)|
sum_of_ratings: \sum_{u \ in U_i(+)} r_{u,i}
sum_of_squared_ratings: \sum_{u \in U_i(+)} r_{u,i} ^2
Same thing for '-'
或者如果你更喜欢dis / likers符号
key = (population_id, item, M, dis/likers)
value =
number: |U_i(dis/likers)|
sum_of_ratings: \sum_{u \ in U_i(dis/likers)} r_{u,i}
sum_of_squared_ratings: \sum_{u \in U_i(dis/likers)} r_{u,i} ^2
cf中间幻灯片24
NB如果你认为每部电影可能是一个分割器,那么第二种形式有2x | item | ^ 2项;那是因为项目 - > (boolean,item,splitter) - 远远小于你的2 ^ | item |评价,你还没有解释。
步骤c 为每个分割器M计算每部电影的估计SE,即SE(U_M)_i
因为总和可以在不同的成员之间分配:
U_M = U_{+M} + U_{-M} + U_{M?}
SE(U_M)_i = SE(U_M?)_i + SE(U_+M) + SE(U_-M)
使用此地图函数显式计算SE(U_{+M})
:
def map(key, value):
'''
key = (population_id, item, M, dis/likers)
'''
value =
count: 1
dist: (r_u,i - r_i)^2
emit key, value
def reduce(key, values):
'''
This function explicitly computes the SE for dis/likers
key = (population_id, item, M, dis/likers)
value= count, dist
'''
emit key, sum(count, sum(dist))
现在我们需要SE(U_{M?})_i
,这是幻灯片24中给出的“琐碎”计算:
SE(?)_i = \sum_{u \in U_i(?)}{r_{u,i}^2} - (\sum r)^2 / |U_i(?)|
当然,我们不会做这么大的事情,但是在讲座中使用上面的评论,并且已经在步骤a中计算了数据(这是我从最后3个方程式中从幻灯片24中得出的结论)< / p>
SE(?)_i = \sum_{u \in U_i}{r_{u,i}^2} - \sum_{u \in U_i('+'/'-')}{r_{u,i}^2} - (...)/ (|U_i| - |U_i('+'/'-'))
所以这个甚至不是Map / Reduce,它只是一个最终的步骤:
def finalize(key, values):
for [k in keys if k match key]:
''' From all entries get
# from step a
key = (population_id, item) value=(nb_ratings, sum_ratings, sum_ratings_squared)
# from step b
key = (population_id, item, M, '+') value=(nb_ratings_likers, sum_ratings_likers, sum_ratings_squared_likers)
key = (population_id, item, M, '-') value=(nb_ratings_dislikers, sum_ratings_dislikers, sum_ratings_squared_dislikers)
# from step c
key = (population_id, item, M, '+') value=(se_likers)
key = (population_id, item, M, '-') value=(se_dislikers)
'''
se_other = sum_rating_squared - sum_ratings_squared_likers - sum_ratins_squared_dislikers - sum_ratings_likers / (nb_ratings - (nb_ratings_likers)) - sum_ratins_squared_dislikers - sum_ratings_likers / (nb_ratings - (nb_ratings_likers))
emit
key: (population_id, splitter, item)
value : se_likers + se_dislikers + se_other
步骤d 最后,最后的步骤计算U_M的SE。它只是先前条目的总和,以及一个简单的Map / Reduce:
对于分割器M:
SE(U_M) = \sum_i SE(U_M)_i = \sum_i SE(U_M?)_i + \sum_i SE(U_+M) + \sum_i SE(U_-M)