写给设计师的人工智能指南:推荐系统
这个系列的文章已经写了5篇了。
点击可以查看往期。
本期更新第6篇文章,
聊聊“推荐系统”。
推荐系统核心的是推荐算法,常用有这几种:
基于内容推荐
协同过滤推荐
基于关联规则推荐
基于效用推荐
基于知识推荐
组合推荐。
最常用的还是组合推荐
Hybrid Recommendation
由于各种推荐方法都有优缺点,所以在实际中,组合推荐经常被采用。
最简单的做法就是分别用基于内容的方法和协同过滤推荐方法去产生一个推荐预测结果,然后用某方法组合其结果。
用的最多的是协同过滤算法,这也是本文要重点介绍的。
协同过滤推荐
Collaborative Filtering Recommendation
协同过滤算法,简称CF,是推荐系统中最古老,也是最简单高效的推荐算法。最早于1989年就提出来了,直到21世纪才得到产业性的应用。应用上的代表在国外有Amazon.com,Last.fm,Digg等等,目前几乎所有的电子商务系统、社交网络,广告推荐,搜索引擎等等,都不同程度的使用了各种形式的推荐系统。
协同过滤是基于这样的假设:
为A用户找到他真正感兴趣的内容的好方法是,根据以往的A、B、C、D...用户产生的数据分析,找到与A用户有相似兴趣的其他用户B、D...,然后将B、D...感兴趣的内容推荐给A用户。
通常,协同过滤算法的形式是一个由用户及商品组成的矩阵,目的是补充用户—商品关联矩阵中所缺失的部分。
最大优点是对推荐对象没有特殊的要求,能处理非结构化的复杂对象,如音乐、电影。但仍有许多的问题,最典型的问题有稀疏问题(Sparsity)和可扩展问题(Scalability)。
1
技术原理
如果要推荐一本书给你,我会在网站上查找一个和你类似的用户,然后将他喜欢的书籍推荐给你。
实现协同过滤,有三种方法:
ALS 交替最小二乘
alternating least squares
ALS算法的核心就是将稀疏评分矩阵分解为用户特征向量矩阵和产品特征向量矩阵的乘积。交替使用最小二乘法逐步计算用户/产品特征向量,使得差平方和最小。通过用户/产品特征向量的矩阵来预测某个用户对某个产品的评分。
基于用户
User-based
基于物品
Item-based
这两个算法的思路基本一致,都是通过计算相似用户或物品,然后计算推荐结果。只是一个是针对用户,一个是针对物品,具体解释可以看下文。
实现User-based或Item-based协同过滤,需要以下几个步骤:
收集用户偏好
找到相似的用户或物品
包括:
计算相似度
相似邻居的计算
计算推荐
2
实现思路
2.1 收集用户偏好
要从用户的行为和偏好中发现规律,并基于此给予推荐,则需要收集用户的偏好信息,这是一个推荐系统效果最基础的决定因素。
典型的用户行为偏好,见下表:
推荐系统依赖不同类型的输入数据,最方便、高质量的是显式反馈数据,包含了用户对感兴趣商品明确的评价。如,Netflix收集的用户对电影评价的星星等级数据,京东、淘宝电商收集的用户好评数据。
显式反馈数据不一定总是找得到,
因此推荐系统可以从更丰富的隐式反馈信息中推测用户的偏好。 隐式反馈数据包括了购买历史、浏览历史、搜索行为甚至鼠标停留点击的动作等等。
如何收集用户的行为数据,需要我们设计系统的时候好好思考。
收集到的数据需要做2个处理,减噪和归一化。
减噪就是去掉无效、无意义的信息,
归一化处理,就是将各类数据除以此类中的最大值,以保证归一化后的数据取值在 [0,1] 范围中。
2.2 相似度的计算
对用户行为进行分析得到用户喜好后,我们可以根据用户喜好计算相似用户和物品,然后基于相似用户或者物品进行推荐:User-based及Item-based。
User-based
基于用户对物品的偏好找到相邻邻居用户,然后将邻居用户喜欢的推荐给当前用户。
Item-based
只是在计算邻居时采用物品本身,而不是从用户的角度,即基于用户对物品的偏好找到相似的物品,然后根据用户的历史偏好,推荐相似的物品给他。
可以看以下两个表格进行理解:
表1:
用户3与用户1相似,用户3所喜欢的物品,用户1应该也喜欢,所以物品D可以推荐给用户1;
表2: 物品A与物品D受欢迎程度类似,所以物品D与A是某一类用户会同时喜欢的物品,物品D可以推荐给用户1。
如上图,可以在二维空间里体会下,分别基于User和Item的差异。
如何找到相似的用户或物品呢?
这个在本系列:
一文有所涉及,计算的是两个特征向量之间的余弦相似度。非常高效、简单的一个算法。
这里也要用到相似度的计算。
相似度是基于向量(Vector),计算两个向量的距离,距离越近相似度越大。
相似度有这些计算方法:
欧几里德距离
最初用于计算欧几里德空间中两个点的距离
皮尔逊相关系数
一般用于计算两个定距变量间联系的紧密程度
余弦相似度
广泛应用于计算文档数据的相似度
谷本系数
是 Cosine 相似度的扩展,也多用于计算文档数据的相似度
选择一种相似度计算方法,然后把所有物品或用户之间的相似度计算出来,接下来,我们就要找到物品或用户的相似邻居,进而推荐啦。
2.3 相似邻居的计算
如何根据相似度找到用户/物品的邻居?
有两种方法:
固定数量的邻居
K-neighborhoods
Fix-size neighborhoods
不论邻居的“远近”,只取最近的 K 个,作为其邻居。
基于相似度门槛的邻居
Threshold-based neighborhoods
从某点出发,计算相似度在k以内的邻居
..........................
..........................
经过计算已经得到了相邻用户和相邻物品,下面介绍如何基于这些信息为用户进行推荐。
2.4 计算推荐
如果是基于Item的算法,则通过预先计算好items之间的相似度,把user 1评分过的items和某个要评分的item D的相似度加权计算预测的评分。
基于User的,则是用提前计算好的User之间的相似度来加权计算。
3
Item-based与User-based之间的对比
3.1 计算复杂度
对于一个电子商务网站,用户数往往大大超过物品的数量,同时物品的数据相对稳定,因此计算物品的相似度不但计算量较小,同时也不必频繁更新。
而对于新闻,博客或者内容类的推荐系统,情况往往相反,物品的数量是海量的,同时也是更新频繁的,如果还是Item-based来计算,那计算量就十分庞大而不可控。
因而,我们需要根据具体的业务场景来决定哪种方式为主。
3.2 适用场景
在非社交网站,比如当当网,如果根据用户给你推荐,“xx用户刚刚购买了这本书”,用户会想“我又不认识xx用户,凭什么我也要买?”,如果是换成基于Item的,“这本书和你以前看的某本书相似”,用户的体验则会更契合场景。
对于社交网站,告诉用户其关注的好友最近浏览了什么,有几个好友也关注了这个内容,往往可以使社交的黏度更大,毕竟是人与人之间的交流嘛。
3.3 多样性和精度
有两种度量角度:
第一种度量方法是从单个用户的角度度量,就是说给定一个用户,查看系统给出的推荐列表是否多样,也就是要比较推荐列表中的物品之间两两的相似度,Item CF 的多样性显然不如 User CF 的好,因为 Item CF 的推荐就是和用户以前看的东西最相似的。
第二种度量方法是对所有用户而言的,考虑整体系统的多样性,也被称为覆盖率 (Coverage)。它是指一个推荐系统是否能够提供给所有用户丰富的选择。
在这种指标下,Item CF 的多样性要远远好于 User CF, 因为 User CF 总是倾向于推荐热门的,另一个侧面说,Item CF 的推荐有很好的新颖性,很擅长推荐长尾里的物品。
所以,尽管大多数情况,Item CF 的精度略小于 User CF, 但如果考虑多样性,Item CF 却比 User CF 好很多。
上图的说明:
给定一个用户,假设他喜欢 3 个领域 A,B,C,A 是他喜欢的主要领域,这个时候我们来看 User CF 和 Item CF 倾向于做出什么推荐:
用 User CF, 它会将 A,B,C 三个领域中比较热门的东西推荐给用户;
用 ItemCF,它会基本上只推荐 A 领域的东西给用户。
所以我们看到因为 User CF 只推荐热门的,所以它在推荐长尾里项目方面的能力不足;
而 Item CF 只推荐 A 领域给用户,这样他有限的推荐列表中就可能包含了一定数量的不热门的长尾物品,同时 Item CF 的推荐对这个用户而言,显然多样性不足。但是对整个系统而言,因为不同的用户的主要兴趣点不同,所以系统的覆盖率会比较好。
以上从原理、特点介绍了协同过滤推荐算法的实现,下面我们动手实验下吧!
4
用Nodejs 动手实验
nodejs有这么一些开源的库可以使用:
Likely.js
recommender
js-recommender
recommender-node
4.1 Likely.js
它需要输入训练矩阵,其中行表示用户,列表示项目。矩阵中的每个条目是用户给予该项目的评级。
比如,下面是一个用户对颜色的喜好的推荐系统
'Red', 'Blue', 'Green', 'Purple'
'John' 1, 2, 3, 0
'Sue' 0, 0, 5, 6
'Joe' 7, 8, 0, 9
步骤1
引用Likely.js库,
创建一个训练矩阵,其中行是用户,列是项目,单元格表示用户对该项目的评级。
比如,inputMatrix [0] [1]是用户0对项目1的评级
矩阵中,数值为0表示需要预测的项目。
const Recommender = require('likely');
var inputMatrix = [
[1, 2, 3, 0],
[0, 0, 5, 6],
[7, 8, 0, 9]
];
我们可以通过另外的2组数组,把这些数据打上标签。
var rowLabels = ['John', 'Sue', 'Joe'];
var colLabels = ['Red', 'Blue', 'Green', 'Purple'];
步骤2
训练模型
var Model = Recommender.buildModel(inputMatrix, rowLabels, colLabels);
Model对象现在包含一个与inputMatrix大小相同的矩阵,包含所有项目的等级。
步骤3
推荐结果
预测Sue所有未评级的项目的等级
var recommendations = Model.recommendations('Sue');
/*
结果
[
[
"Blue",
4.8167148275771
],
[
"Red",
3.348124204068041
]
]
*/
或者列出一个用户的所有item的预测结果
var allItems = Model.rankAllItems('John');
/*
结果
[
[
"Purple",
3.068834803624972
],
[
"Green",
2.9744619078106145
],
[
"Blue",
1.9912411830354393
],
[
"Red",
1.0367047386687587
]
]
*/
4.2 recommender
recommender包含通常在推荐系统中使用的tf-idf,Collaborative Filtering以及Global Baseline Approach。
每个API方法都具有同步和异步方式。
我用的是正在开发的基于Electron的JS Playground桌面级APP。
在安装recommender的时候,碰到了NODE版本问题。
Error: The module ‘xxxxxxx’ was compiled against a different Node.js version using NODE_MODULE_VERSION 46. This version of Node.js requires NODE_MODULE_VERSION51. Please try re-compiling or re-installing
还有其他nodejs的库,在electron引用的时候,也经常会碰到的node版本不一致的情况,我们可以采用下列方案解决:
先安装下electron-rebuild
npm install --save-dev electron-rebuild
设置下npm
export npm_config_disturl=https://atom.io/download/atom-shell
export npm_config_target=1.6.10
export npm_config_arch=x64
export npm_config_runtime=electron
碰到需要重建node版本的,用下面这个命令安装包即可
HOME=~/.electron-gyp npm install recommender@3.0.0 --save
4.3 js-recommender
输入的格式,如下图
标签跟分数一并输入,稍有点麻烦,如果是外部导入的文件,还得处理下,通过for循环来写入。
输入的数据,跟预测的数据:
4.4 recommender-node
可以从外部直接导入csv文件,或者是json文件,计算后,会将结果输出一个json文件,方便预测时直接调用。
最后,大家可以到网上下载一些开源的数据集进行实验,对比下4个库的推荐结果哈~
本公众号定期更新关于
设计师、程序员发挥创意
互相融合的指南、作品。
主要技术栈:
nodejs、react native、electron
欢迎关注,转发~
欢迎长按二维码
关注本号