mahout学习之推荐算法

推荐的定义

推荐算法可以分为三大类,基于用户的,基于物品的和基于内容的,前两者均属于协同过滤的范畴,仅仅通过用户与物品之间的关系进行推荐,无需了解物品自身的属性。而几乎内容的推荐技术很有用,但是必须与特定领域相结合,比如推荐一本书就必须了解书的属性,作者,颜色,内容等等。但是这些知识无法转移到其他领域,比如基于内容的图书推荐就对推荐哪道菜比较好吃毫无用处。 所有mahout对基于内容的推荐涉及很少。

基于用户的推荐

算法

基于用户的推荐算法来源与对相似用户爱好的总结,一般过程如下:

for (用户u尚未表达偏好的) 每个物品i
    for(对i有偏好的)每个其他用户v
        计算u和v之间的相似度s
        按权重为s将v对i的偏好并入平均值
return 值最高的物品(按加权平均排序)

看上去挺简单,但是,每个物品都检查速度太慢,一般会先计算出一个最相似用户的领域,然后仅考虑这些用户评价过的物品。

for(每个其他用户w)
    计算用户u与用户w的相似度s
    按相似度排序后,将位置靠前的用户作为领域n
for(n中用户有偏好,而用户u无偏好的)每个物品i
    for(n中用户对i有偏好的)每个其他用户v
        计算用户u与v的相似度s
        按权重s将v对i的偏好计入平均值
return 值最高的物品

mahout的具体实现

根据以上算法,可以具体化为以下步骤: 1. 数据模型,由DataModel实现 2. 用户间的相似性度量,由UserSimilarity实现 3. 用户邻域的定义,由UserNeighborhood实现 4. 推荐引擎,由一个Recommender实现

一个具体的例子如下:

        //存储并计算提供计算所需的偏好,用户以及物品数据
        DataModel model =
                new FileDataModel(new File("D:\\mahoutData\\intro.csv"));
        //比较两个用户之间的相似度
        UserSimilarity similarity =
                new PearsonCorrelationSimilarity(model);
        //明确与给定用户最相似的一组用户
        UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);
        //合并上述所有组件为用户推荐物品
        Recommender recommender = new GenericUserBasedRecommender(
                model, neighborhood, similarity);
        List<RecommendedItem> recommendations =
                recommender.recommend(1, 1);
        for (RecommendedItem recommendation : recommendations) {
            System.out.println(recommendation);
        }

相似性度量

基于皮尔逊相关系数的相似度

要理解Pearson相关系数,首先要理解协方差(Covariance),协方差是一个反映两个随机变量相关程度的指标,如果一个变量跟随着另一个变量同时变大或者变小,那么这两个变量的协方差就是正值,反之相反,公式如下:

Pearson相关系数公式如下:

由公式可知,Pearson相关系数是用协方差除以两个变量的标准差得到的,虽然协方差能反映两个随机变量的相关程度(协方差大于0的时候表示两者正相关,小于0的时候表示两者负相关),但是协方差值的大小并不能很好地度量两个随机变量的关联程度 ,为了更好的度量两个随机变量的相关程度,引入了Pearson相关系数,其在协方差的基础上除以了两个随机变量的标准差,pearson是一个介于-1和1之间的值,当两个变量的线性关系增强时,相关系数趋于1或-1;当一个变量增大,另一个变量也增大时,表明它们之间是正相关的,相关系数大于0;如果一个变量增大,另一个变量却减小,表明它们之间是负相关的,相关系数小于0;如果相关系数等于0,表明它们之间不存在线性相关关系。 一个简单的例子:

用户

物品

喜欢的程度

1

101

5.0

1

102

3.0

1

103

2.5

2

101

2.0

2

102

2.5

2

103

5.0

2

104

2.0

3

101

2.5

3

104

4.0

3

105

4.5

3

107

5.0

4

101

5.0

4

103

3.0

4

104

4.5

4

106

4.0

5

101

4.0

5

102

3.0

5

103

2.0

5

104

4.0

5

105

3.5

5

106

4.0

第一列代表用户,第二列代表物品,第三列代表喜欢的程度,0为不喜欢,5为很喜欢。 计算他们的皮尔逊相关系数,得到如下表格:

皮尔逊相关系数也并不是总靠谱,比如两个人只看过2部相同电影,评价相同或者两个人看过200部相同电影,绝大部分评分相同。依据后者推荐明显比前者靠谱,但是前者的皮尔逊相关系数就是高于后者。 为了解决上述问题,mahout的PearsonCorrelationSimilarity 方法引入了权重的概念,将Weighting.WEIGHTED作为第二个参数传递进去即可使得统计较多数量的物品时,相关值向1.0或-1.0偏移,而物品数量少的时候,向均值偏移。

基于欧式距离的相似度

使用这个方法将代码中的UserSimilarity改为 new EuclideanDistanceSimilarity(model)即可。 欧几里得距离不多赘述,用户即为多维空间中的点,不同的物品即为不同的维度,用户对物品的偏好向量即为坐标,然后算一下距离即可,为了结果与相似度正相关,通常取1/(1+d)为结果,d为欧几里得距离。

基于余弦相似性的相似度

和欧式距离类似,一个多维坐标系中,两个点越近,其夹角越小。但是mahout中并没有具体的方法实现,因为当两个输入序列均值为0时,余弦相似度和皮尔逊距离归结为同一个计算过程。所以在协同过滤的时候直接使用皮尔逊相似度即可。

基于斯皮尔曼相关系数的相对顺序的相似度

斯皮尔曼相关系数本质上时是皮尔逊相关系数的一个变体,他不是基于原始数据,而是只保留了原始数据的相对顺序,比如(1.5,5.0,2.6)就变为(3,1,2)。这种办法无法说好或不好,只能视情况而定。

和前面一样,把UserSimilarity换为SpearmanCorrelationSimilarity即可。值得注意的一点事,这个算法执行非常慢。。。。慢到mahout in action这本书是这么说的: Run it, and take a long coffee break. Turn in for the night. It won’t finish anytime soon. 数据量较大的话可以喝杯咖啡或者睡觉了。。。

基于谷本系数的忽略偏好值的相似度

这种机制不关心偏好值的大小,只关心是否表达过相似度。

谷本系数即为交集与并集的比值,当用户偏好完全重合,比值为1,当完全不重合,比值为0,可以用简单的数学变换让结果落到[-1 , 1]上,即相似度 = 2* 相似度 -1。

用TanimotoCoefficientSimilarity 替换UserSimilarity即可。

基于对数似然比的相似度

这个涉及的数学知识。。。搞不明白。但是计算的结果可以解释为发送发生重叠的非偶然概率。用 TanimotoCoefficientSimilarity替换UserSimilarity即可。其结果往往优于谷本相似度。

相似度的缓存机制

因为计算相似度需要耗费大量时间,所以可以直接缓存在内存中:

UserSimilarity similarity = new CachingUserSimilarity(new SpearmanCorrelationSimilarity(model), model);

当然这回占用很多内存。

用户邻域

选择用户邻域直接影响到最后的结果,一般有如下两种选择邻域的方法:

固定大小的邻域

这种算法其实就是knn(k nearest neighborhood),根据一些方法找到两个用户之间的距离,比如根据属性向量得到欧氏距离,然后寻找距离最近的k个。 这种算法下k的定义很重要,并不是越大越好,比如下图这种情况:

选择k为3就比k为5精度要高,所以往往需要细致的调参来确定一个合适的k值。上面的代码即为使用此种方法。

基于阈值的邻域

这种方法直接选择那些很相似的用户而忽略其他人,设置一个阈值,选择所有超过这个阈值的用户

与上面的最大不同点在于,只要满足这个阈值,不管有多少个,都会被统计在内。通常使用皮尔逊相关系数作为阈值的根据。 使用这种算法需要简单修改下代码,将

//明确与给定用户最相似的一组用户
        UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);

改为:

    UserNeighborhood neighborhood = new ThresholdUserNeighborhood(0.7, similarity, model);

阈值的设置同样关键,也需要多次测试后得出。

基于物品的推荐

基于物品的推荐与基于用户的推荐的本质区别在于,以物品的相似度为基础,而非用户。

算法

for(用户u尚未表达偏好的)每个物品i
    for(用户u表达偏好的)每个物品j
        计算i与j之间的相似度s
        按s为权重将j与i的相似度并入平均值
return 值最高的物品(按加权平均排序)

和基于用户的推荐的最主要的差别在于,用户的喜好在不停的变化,但是物品本身不容易变化。因为变化不大,所以适合预先计算相似度,可以大大提升运行时候的推荐效率。GenericItemSimilarity可以用来存储ItemSimilarity的计算结果。

mahout的具体实现

public Recommender buildRecommender(DataModel model) 
 throws TasteException {
 ItemSimilarity similarity = new PearsonCorrelationSimilarity(model);
 return new GenericItemBasedRecommender(model, similarity);
}

相似度的判别方法和基于用户的一致,大部分的相似度判别方法都同时实现了两种接口。 同时依照算法并没有计算邻域的步骤,因为已经有了一些用户表达偏好的物品,这和邻域的计算结果是类似的。 以下是不同的相似度方法的结果:

当物品数量小于用户数量时候(比如电影的数量远小于看电影的人),基于物品的推荐快于基于用户的推荐。

slope-one推荐算法

这时另外一种基于物品的推荐算法。它基于新物品与用户评估过的物品之间的偏好值差异来预测用户对新物品的偏好值。可以看作用已经评估过的物品做参数求出一个线性函数,然后把新的物品代入,得到新的偏好值。

算法

//预处理,完成所有物品之间偏好值差异
for (每个物品i)
    for(每个其他物品j)
        for(对i和j均有偏好的每个用户u)
            将物品对(i,j)的偏好值差异加入u

//然后执行推荐算法
for(用户u未表达偏好的每个物品i)
    for(用户u表达过偏好的每个物品j)
        找到i与j之间的平均偏好值差异
        添加该差异到u对j的偏好值
        添加其至平均值
return 值最高的物品

由算法可以得出,其性能不受用户数目影响,仅依赖于物品偏好值之间的平均差异,可以预先计算好,当一个偏好值改变,只需改变其相关的差异值,但内存消耗较大,O(n^2),n为物品数。

mahout的具体实现

DiffStorage diffStorage = new MemoryDiffStorage(
 model, Weighting.UNWEIGHTED, Long.MAX_VALUE));
return new SlopeOneRecommender(
 model,
 Weighting.UNWEIGHTED,
 Weighting.UNWEIGHTED, 
 diffStorage);

slope-one算法和皮尔逊相关系数有一样的问题,忽略了数量对差异可靠性的影响,同样也可以使用加权的方式来补偿,上述代码手动关闭了权重,默认开启。

内存考虑

因为占用内存太大,所以需要把偏好值差异序列化到磁盘,这时候可以使用JDBC连接mysql,不多做描述。

基于内容与基于模型的推荐算法

这两者虽然现在并未在mahout里实现,但却是未来的发展方向,读者有兴趣自行百度~

参考资料

https://www.zhihu.com/question/19734616?sort=created 《Mahout In Action》 http://blog.csdn.net/xidianliutingting/article/details/51916578

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AI科技大本营的专栏

AI 行业实践精选:通过机器学习刺激销量——如何利用NLP挖掘潜在客户

【AI100 导读】在这篇博客中,作者会向大家介绍如何以更有效的方式通过 Xeneta 进行营销,会训练一个机器学习算法,通过对于公司的描述来预测潜在客户的质量...

3508
来自专栏编程

7步让你从零开始掌握Python机器学习!

这篇文章旨在通过7个步骤,将最少的机器学习知识转化为知识型实践者,所有这一切都在使用免费的材料和资源。这个大纲的主要目标是帮助你通过许多可用的免费选项; 有很多...

1949
来自专栏大数据挖掘DT机器学习

关联规则挖掘综述

本文介绍了关联规则挖掘的研究情况,提出了关联规则的分类方法,对一些典型算法进行了分析和评价,指出传统关联规则衡量标准的不足,归纳出关联规则的价值衡量方法,展望了...

3899
来自专栏人工智能头条

Etsy 数据科学主管洪亮劼带你读:WWW 2017 精选论文

1384
来自专栏AI科技评论

深度学习——你需要了解的八大开源框架

导读:深度学习(Deep Learning)是机器学习中一种基于对数据进行表征学习的方法,深度学习的好处是用非监督式或半监督式的特征学习、分层特征提取高效算法来...

4406
来自专栏程序生活

QA-对话系统-问答系统-聊天机器人-chatbot相关资源1 简介2 博客推荐论文3 项目4 相关链接

4652
来自专栏数据科学与人工智能

【应用】信用评分:第3部分 - 数据准备和探索性数据分析

因此,**数据准备是任何数据挖掘项目的关键方面,包括信用评分卡的开发。 **这是CRISP-DM周期中最具挑战性和耗时的阶段。 项目总时间中至少70%,有时多于...

991
来自专栏AI科技评论

干货 | Siri 语音识别的小心机:你在哪里,就能更准确地识别那附近的地址

AI 科技评论按:这篇文章来自苹果机器学习日记(Apple Machine Learning Journal)。与其他科技巨头人工智能实验室博客的论文解读、技术...

972
来自专栏AI星球

我与Python--从Hacker到探索Deep Learning

进入大学之后,我们逐渐“被教授”了C、C++、Java等编程语言,但为什么我会选择python作为最喜欢的编程语言呢?

863
来自专栏量子位

强化学习算法Q-learning入门:教电脑玩“抓住芝士”小游戏

王瀚宸 编译自 practicalai.io 量子位 报道 | 公众号 QbitAI 这篇文章打算教你使用强化学习中的Q-learning算法,让电脑精通一个简...

3564

扫码关注云+社区