分享

Spark 高级分析:第三章第8,9,10节

feilong 2017-12-22 08:23:49 发表于 连载型 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 5922
本帖最后由 feilong 于 2017-12-22 08:26 编辑
问题导读

1.ALS.trainImplicit()参数有哪些?各自的意义是什么?
2.Spark MLlib的ALS能否支持向所有用户推荐?
3.Spark MLlib的ALS是否支持实时推荐?




上一篇:Spark 高级分析:第三章第6,7节
http://www.aboutyun.com/forum.php?mod=viewthread&tid=23520&extra=

8.超参数的选择

但现在为止,用来构建MatrixFactorizationModel的超参数值还没有提供注释。它们并不是通过算法来获知的,而必须被调用者关闭。ALS.trainImplicit()的参数是:
  • rank=10:模型中潜在因子的数量,或者等价地表示用户特征和产品特征矩阵中的列数k。在不平凡的情况下,这也是他们的秩。
  • iterations = 5:因式分解运行的迭代次数。更多的迭代需要更多的时间,但可能会产生更好的分解。
  • lambda = 0.01:一个标准的过拟合参数。更高的值抵御过拟合,但值太高会损害因式分解的精度。
  • alpha = 1.0:在分解过程中控制观察到的与未观察到的用户产品交互的相对权重。

rank, lambda 和alpha都可以被认为是模型的超参数。(迭代更多地是对分解中使用的资源的约束。)这些并不是矩阵中矩阵的值,它们只是它的参数,由算法选择。这些超参数反而是构建自身过程的参数。

上面使用的值不一定是最优的。选择好的超参数的值在机器学习中是一个常见的问题。选择值的最基本的方法是简单地尝试值的组合,并为每一个值评估一个度量值,然后选择产生最佳值的组合。

例如,下面尝试8种可能的组合:秩= 10或50、λ=1或0.0001、α=1或40。这些值仍然是一个猜测,但选择覆盖广泛的参数值。结果按最高AUC分数打印出来:
[mw_shl_code=scala,true]val evaluations =
for (rank <- Array(10, 50);
lambda <- Array(1.0, 0.0001);
alpha <- Array(1.0, 40.0))
yield {
val model = ALS.trainImplicit(trainData, rank, 10, lambda, alpha)
val auc = areaUnderCurve(cvData, bAllItemIDs, model.predict)
((rank, lambda, alpha), auc)
}
evaluations.sortBy(_._2).reverse.foreach(println)
...
((50,1.0,40.0),0.9776687571356233)
((50,1.0E-4,40.0),0.9767551668703566)
((10,1.0E-4,40.0),0.9761931539712336)
((10,1.0,40.0),0.976154587705189)
((10,1.0,1.0),0.9683921981896727)
((50,1.0,1.0),0.9670901331816745)
((10,1.0E-4,1.0),0.9637196892517722)
((50,1.0E-4,1.0),0.9543377999707536)[/mw_shl_code]
有趣的是,参数alpha在40时似乎总是比1好。(对于好奇的人来说,在上面的原始ALS文件中,有40个是默认值。)这可以粗略地解释为,这表明该模型更侧重于用户所听的内容,而不是他或她不听的内容。

更高的lambda看起来也稍微好一些。这表明该模型稍微容易被过度拟合,因此需要一个更高的lambda来抵制尝试适应每个用户给出的稀疏输入。在接下来的章节中,我们将会更加详细地回顾这个问题。

功能的数量没有明显的区别。尽管分数在绝对值上并没有多少变化,但在最高和最低得分组合中都出现了50个。这可能表明,正确的特性数实际上高于50,而且这些值在太小的情况下是相似的。

当然,这个过程可以在不同的值范围内重复,或者更多的值。这是一种选择超参数的蛮力方法。然而,在这样一个拥有TB级内存和数百个内核的集群中并不少见,并且像Spark这样的框架可以利用并行性和内存来加快速度,它变得非常可行。

甚至不需要严格地理解超参数是什么意思,尽管知道值的正常范围是什么是有帮助的,以便开始搜索一个既不太大也不太小的参数空间。

9.计算推荐

在上面的超参数的最佳集合的时刻,一个新的模型推荐用户2093760是什么?
[mw_shl_code=scala,true]50 Cent
Eminem
Green Day
U2
[unknown][/mw_shl_code]
有趣的是,这对两个嘻哈歌手来说更有意义。[unknown]显然不是艺术家。询原始数据集显示,它发生了429,447次,几乎进入了前100 !这是一些没有艺术家的默认值,可能是由某个歌曲记录客户端提供的。它不是有用的信息,应该从输入中删除,然后再开始。这是一个例子,说明数据科学的实践经常是迭代的,关于数据的发现是在整个过程的各个阶段发生的。

该模型可用于为所有用户提供建议。这可能在批处理过程中非常有用,它可以重新计算模型,并根据数据的大小和集群的速度,每小时甚至更少地重新计算推荐。

然而,目前,Spark MLlib的ALS实现不支持向所有用户推荐的方法。每次向一个用户推荐是可能的,尽管每个用户都将启动一个耗时数秒的短期分布式作业。这可能适用于对小群体用户的快速重新计算推荐。这里将从数据对100个用户计算推荐并打印如下:用户-> 艺术家1,艺术家2 ,......
[mw_shl_code=scala,true]val someUsers = allData.map(_.user).distinct().take(100)
val someRecommendations =
someUsers.map(userID => model.recommendProducts(userID, 5))
someRecommendations.map(
recs => recs.head.user + " -> " + recs.map(_.product).mkString(", ")
).foreach(println)[/mw_shl_code]
这里,推荐刚刚打印出来。它们可以很容易地写入到像HBase这样的可在运行时提供快速查找外部存储库中。

有趣的是,这整个过程也可以用来向艺术家推荐用户。这可以用来回答诸如“哪100个用户最有可能对X的新专辑感兴趣”之类的问题。这样做只需要在解析输入时交换用户和艺术家字段:
[mw_shl_code=scala,true]rawUserArtistData.map { line =>
...
val userID = tokens(1).toInt
val artistID = tokens(0).toInt
...
}[/mw_shl_code]

10.下一步

当然,我们可以花更多的时间来调整模型参数,在输入中找到和修正异常,就像[未知]艺术家一样。

例如,对播放计数的快速分析显示,用户2064012播放艺术家4468的音乐是惊人的439,771次!艺术家4468是一个令人难以置信的成功的交替金属乐队,在之前的推荐中出现。假设平均歌曲长度为4分钟,这是超过33年的“Chop Suey!’”和“B.Y.O.B.”。当乐队在1998年开始录制唱片时,这似乎要在7年内一次播放4到5首歌曲。即使是铁杆粉丝,这也很难相信。这是电子垃圾,或者是数据错误,是生产系统必须处理的真实数据类型的另一个例子。

ALS不是唯一可能的推荐算法。然而,在这个时候,它是唯一由Spark MLlib支持的然而,MLlib还支持非隐式数据的变体。它的使用是相同的,只是模型是用ALS.train()方法构建的。当数据是像rating一样的,而不是像count一样的时候,这是合适的。例如,当数据集是1 - 5级的艺术家的用户评分时,它是合适的。从各种推荐方法返回的评价对象的结果评级字段实际上是一个估计的评级。

之后,其他推荐算法可以在Spark MLlib或其他库中使用。

在生产中,推荐引擎经常需要在实时的情况下提出建议,因为它们在电子商务网站这样的环境中使用,当客户浏览产品页面时,建议经常被要求。正如上面所提到的,在NoSQL存储中预计算和存储建议是一种合理的方法,可以在规模上提供建议。这种方法的一个缺点是,它需要为所有可能需要推荐的用户提供预计算建议,这可能是他们中的任何一个。例如,如果每天有100万用户访问一个站点,那么每天就能计算出100万用户的推荐量,这就浪费了99%的精力。

根据需要,联机计算建议会更好。当用MatrixFactorizationModel为一个用户计算推荐时,一个分布式操作花费几秒钟是必要的,因为MatrixFactori zationModel特别大,实际上是一个分布式数据集。其他的模型也不是这样,它们的得分要快得多。像Oryx这样的项目试图通过高效地访问内存中的模型数据来实现像MLlib这样的库的实时随需应变的推荐。






没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条