前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Recommended System

Recommended System

作者头像
西红柿炒鸡蛋
发布2018-10-10 11:58:26
5640
发布2018-10-10 11:58:26
举报
文章被收录于专栏:自学笔记自学笔记

推荐系统

推荐系统的核心问题就在于为用户推荐与其兴趣相似度比较高的商品。比如在微博上,用户至上想打发时间,并不是想准确的查看某条信息,在首页中查看每一条微博,为了帮助他筛选出一批他们可能感兴趣的信息,此时就需要分析出该用户的兴趣,从海量信息中选择出与用户兴趣相似的信息,并将这些信息推荐给用户。推荐系统就是这样,根据用户的历史和社交情况推荐与其喜好相符的商品或信息。

这时候就需要一个相似度函数

,函数

可以计算商品和我用户之间的复杂度,向用户推荐相似度较高的商品。为了能够预测出函数

,可以利用到历史诗句主要有:用户的历史行为数据,与该用户相关的其他用户信息,商品之间的相似性,文本描述等等。假设集合

表示所有的用户,集合

表示所有需要推荐的商品。函数

表示商品s到用户c之间的有效用函数,例如:

其中,R是一个全体排序集合。对于每一个用户

,希望从商品的集合上选择出商品,即

,以使得应用函数

的值最大。

在功业场景一般都是这样,线下部分可以随意发挥,Python,MATLAB等等都可以,但是到线上部分就要考虑各种情况了,比如效率和并非,甚至是可移植可拓展性等等。

推荐系统的评估方法

准确度

这个概念应该比较熟悉的了,对于准确度的评估,也要分系统来看,推荐系统有两种,一种是打分系统,一种就是TopN系统。打分系统其实就相当于是一种拟合方法,拟合用户的打分过程,而TopN系统就是给出前N个好的商品而已,所以这两个的准确度的评判标准是不一样的。对于打分系统:设

为用户

对物品

的实际打分,

为预测得分,误差判定标准有两个:

对于TopN的推荐系统,

代表推荐的内容,

就是用户选择的内容:

这两个评价指标是互相牵制的,准确率高制约着召回率。

覆盖率

表示对物体长尾的发掘能力。有时候卖的多的物品会卖的更多,因为很多人看到别人也买就会跟风,但这样就会造成穷的会更穷,富的会更富,所以为了消除这种两极分化,也叫马太效应。可以用一个熵的概念来衡量

熵其实是个人都知道,平均的时候是最大的,这就有利于消除贫富差距。

多样性

多样性表示的就是推荐物品的种类多样程度,如果推荐的物品基本都是鞋子一类的,那么多样性就很差了,首先用

来表示这两个物品的相似度,多样性表示:

以上就是一些主要的推荐评价指标,当然还是很多,比如新颖度,惊喜度,信任度,实时性等等。

冷启动

冷启动指的就是在一个新用户和新商品进来的时候,推荐系统对这个用户和商品是一无所知的,如何在这种情况下做到有效的推荐,这就叫做冷启动问题了。对于一个一无所知的用户,解决方法有很多:可以收集一些非常热门的商品,收集一些信息,在用户注册的时候收集一些信息,比如弹出来问一下你喜欢什么,或者问一下你感兴趣的是什么。很多游戏知乎都会有这种举措。在用户结束之后还可以进行一些互动的小游戏来确定用户喜欢还是不喜欢。

对于新商品,可以根据本身的属性,求与原来商品相似度。可以用item-based-CF推荐出去。

相似度的衡量

欧式距离,是个人都知道,不提了。

Pearson Correlation相似度:

<x,y>指的就是內积操作、皮尔逊相似度的好处就在于对于级数不敏感,级数相差过大带来的影响不大。

余弦相似度:

这个就不用多说了,一般就是用在了文本编码之后的向量相似度比较,因为这时候很多向量都不在欧式空间上了,一般就用他们夹角的大小来

推荐算法

基于内容的推荐
基于关联规则的推荐
协同过滤的推荐
基于知识的推荐
基于图的推荐
组合推荐

当然不会讲解这么多,只会提到一两个。

基于内容的推荐系统

基于内容就是基于用户喜欢的物品的属性/内容进行推荐,需要分析内容,无需考虑用户和用户直接的关系。通常就是在文本相关的产品上进行推荐。所以一般就是通过内容上的关键词进行推荐,然后编码比对物品内容的异同进行推荐。事实上编码之后就可以随意发挥了,直接使用KNN都是可以的。

最简单的文本推荐,对于一份文本,首先就是要建立资料这个时候就是叫编码过程了,因为不可能把里面的文字都抽取出来,这样工作量非常大,使用首先就是要分词去掉重复的词语,然后抽取关键字做编码。TF-IDF,词袋模型,ont-hot编码,词

在文件

中权重

都是可以的,得到这些向量之后,就可以用相似度衡量,选择合适的算法做相似度排序选择了。比如对于书本《Building data mining application for CRM》这个本书感兴趣。

以上是商品总和。

出现过的单词扣一,没有的都是0,这种编码叫做one-hot编码,这里商品少,单词也就那么几个,所以ont-hot编码不长,就是一点点而已。比较牛逼点的就是TF-IDF了:

把文档出现词的概率算了进来。得到这些向量之后只需要做近似就好了,比如KNN最简单的。

协同过滤的推荐

NeiNeighborhood-based Algorithm是一种基于近邻的推荐,协同过滤有两种,一种是基于用户的协同过滤,一种是基于物品的协同过滤。

user-based CF

其实过程是非常简单的,简单到飞起。首先我们是要得到一个相似度矩阵,这个相似度矩阵首先是一个对称的,其次它的对角线都是0,。计算完用户之间的相似度之后利用用户之间的相似度为没有打分的项打分。其实就是

找到当前这个用户没有打分的商品,然后把对这个商品评价过的用户的得分乘上相似矩阵的对应权重相加即可。

代码实现

工具包的实现:

求余弦相似度:

代码语言:javascript
复制
def cos_sim(x, y):
    numerator = x * y.T
    denominator = np.sqrt(x * x.T)
    return (numerator / denominator)[0, 0]

求相似度矩阵:

代码语言:javascript
复制
def similarity(data):
    m = np.shape(data)[0]
    w = np.mat(np.zeros((m, m)))
    for i in range(m):
        for j in range(i, m):
            if j != i:
                w[i, j] = cos_sim(data[i, ], data[j, ])
                w[j, i] = w[i, j]
            else:
                w[i, j] = 0
    return w

求top N的商品是什么:

代码语言:javascript
复制
def top_k(predict, k):
    top_recom = []
    len_result = len(predict)
    if k >= len_result:
        top_recom = predict
    else:
        for i in range(k):
            top_recom.append(predict[i])
    return top_recom

基于用户的协同过滤:

代码语言:javascript
复制
def user_based_recommend(data, w, user):
    m, n = np.shape(data)
    interaction = data[user, ]
    not_inter = []
    for i in range(n):
        if interaction[0, i] == 0:
            not_inter.append(i)
    predict = {}
    for x in not_inter:
        item = np.copy(data[:, x])
        for i in range(m):
            if item[i, 0] != 0:
                if x not in predict:
                    predict[x] = w[user, i] * item[i, 0]
                else:
                    predict[x] = predict[x] + w[user, i] * item[i, 0]
    return sorted(predict.items(), key=lambda  d:d[1], reverse=True)

相似度矩阵

为每一个用户所推荐的商品。

item_based CF

也是一样,只需要把数据转置一下就好了。

代码语言:javascript
复制
def item_based_recommend(data, w, user):
    m, n = np.shape(data)
    interation = data[:, user]
    not_inter = []
    for i in range(n):
        if interation[0, i] == 0:
            not_inter.append(i)

    predict = {}
    for x in not_inter:
        item = np.copy(interation)
        for j in range(m):
            if item[0, j] != 0:
                if x not in predict:
                    predict[x] = w[x, j] * item[0, j]
                else:
                    predict[x] = predict[x] + w[x, j] * item[0, j]
    return sorted(predict.items(), key=lambda d:d[1], reverse=True)

相似度矩阵

每位用户的推荐。

user-based vs item-based 这两种方法各有优缺点。对于UserCF,适用于用户较少的场景,如果用户是非常多的的情况下,计算用户相似度矩阵的代价是很大的。这个时候如果物品相对用户要少,那么就可以用ItemCF来计算相似度矩阵。对于两种算法的领域也有很大的区别,UserCF的时效性较强,对于用户兴趣不太明显的领域是有可能会推荐出来的,也就是说覆盖性会好一些,因为它是根据用户之间的相似度决定的,用户之间的兴趣点是相似但是不会都相同的,所以可以削弱马太效应。而对于ItemCF,这个物品相似度是死的,相似的基本都很相似,所以可能会有很大的长尾,一般是用户需求很强烈的地方使用。还有冷启动问题,对于一个新用户进来的时候,不能立刻对他进行推荐,因为用户的相似度矩阵是一段时间后离线计算的,新物品上线之后一旦有用户对这个商品产生行为就可以将物品推荐给它产生行为的用户了。但是这样就没有办法在不离线更新相似度表的情况下将新物品推荐给用户了。还有就是推荐理由,对于UserCF,用一个我根本不认识的人的习惯来推荐给我,对于用户的说服力肯定是不够的,商品就不一样了,商品是死的。 CF的优缺点 优点:基于用户的行为对于推荐内容是不需要先验知识的,只需要建立用户或者是商品的相似矩阵即可,结构很简单,在用户丰富的情况下效果很好,而且很简单。 缺点:需要大量的行为,也就是历史数据,需要通过完全相同的商品关联起来,相似的不行。而且·使用CF是有前提的了,要求就是用户只会完全取决于之前的行为,上下文是没有关系的了。而且在数据稀疏的情况下效果是不好的,还可能需要二度关联,因为如果一下商品没有什么人买,基本就没得推荐了。

基于隐语义的推荐

基于隐语义的推荐,其实就是矩阵分解。之前写过一篇叫Matrix Factorization的文章讲的就是这个:https://www.jianshu.com/p/af49053832c5

首先对用户进行一些简单的编码,因为用户如果是把名字记上去是做不了计算的,所以我们把用户进行编码,比如有4个用户,一号用户就

,二号

等等以此类推。

如果是使用神经网络来解决这个问题,首先就是要设计一个网络,

,N输入用户的数量,d就是网络的维度,M就是输出的结果,M就是物品的数量,因为最后的输出就是用户对商品的评分。

但实际上还是有一个问题,就是对于激活函数,也就是非线性函数是否需要的问题。事实上是不需要的,因为如果只有一个

是有效的,那么这个

就是只有一行有效的,所以只会有一个x经过了tanh函数,从效果上讲一个tanh(x)和x是没有什么区别的。所以可以忽略非线性:

整合一下公式

由于x就是一行有效,所以

所以,第m个用户的第n个商品的评分就是

这样就分解得到了我们要的公式,最后求导即可。事实上分解出来的两个矩阵里面的变量代表的数据的意义其实是不明确的,也就是说比较抽象,怎么想象都行。分解出来的矩阵

,k代表的就是分解的度,分解的越多有可能会过拟合,所以这里也是可以加正则化的。

不要尝试的去理解所有分解的赢语义,这是没有意义的,比如神经网络的每一个神经元,事实上你们是不知道他们到底是在干什么,只是知道他们在观察而又,这里也是一样的,这里面分解出来的东西,如果是电影,你可以说是喜剧成分,武大成分,也可以说是演员等等,相当于一指示变量而已,只是指明了这个物品是多少分,但是没有给出具体的意义。

具体的公式之前的博客都有,例子也提到,这里就不重复了。

上面提到的只是最简单的MF模型,但是这类模型有一个缺点,他们分解出来的东西会有负数,这就尴尬了,因为很少有变量因素会其负作用的,于是便出现了非负矩阵分解。

非负矩阵分解出现的根本原因就矩阵分解解释性差的问题。

NMF

矩阵非负分解,这个就有点厉害了。首先引入一下KL离散度:

KL损失函数 对于KL散度的推导其实很简单:

所以一阶Tayor逼近的误差是:

代入熵

这样推导出来了。平方差损失函数对应着高斯分布,那么KL肯定也对应着另一个分布——泊松分布:

因为

是随机数,所以求一下期望:

所以KL离散度就对应了泊松分布。

对于这个KL离散度:

KL离散度一定是大于等于0的,当

的时候,这个离散度就是等于0的了,所以我们要求的就是不断的

即可。

所以现在NMF的损失函数有两种了①均方差损失函数:

;②KL离散度:

,还是用第一种吧!

问题来了,既然是非负数的,怎么保证是正数是一个问题,这里有一个很牛逼的技巧:

所以更新方式:

要做的就是设计一个n,使得乘上之后可以抵消前面的Q即可。

,带进去之后:

使用KL离散也是一样的。

代码实现
代码语言:javascript
复制
def train(V, r, maxCycles, e):
    m, n = np.shape(V)
    W = np.mat(np.random.random((m, r)))
    H = np.mat(np.mat(np.random.random((r, n))))

    for step in range(maxCycles):
        V_pre = W * H
        E = V - V_pre
        err = 0.0
        for i in range(m):
            for j in range(n):
                err += E[i, j] * E[i, j]
        if err < e:
            break
        if step % 1000 == 0:
            print("\Interator: ", step, " Loss: ", err)
        a = W.T * V
        b = W.T * W * H
        for i in range(r):
            for j in range(n):
                if b[i, j] != 0:
                    H[i, j] = H[i, j] * a[i, j] / b[i, j]
        c = V * H.T
        d = W * H * H.T
        for i in range(m):
            for j in range(r):
                if d[i, j] != 0:
                    W[i, j] = W[i, j] * c[i, j] / d[i, j]
    return W, H

效果:

效果还是可以的。

CF VS隐语义

隐语义其实还有一种分解方式,就是SVD,SVD也可以的,但是SVD的分解是

,而且如果原矩阵是有很多缺省值的话,那么SVD就会用0填充,这样不太好的。相比之下CF跟简单,而且可解释性也强,但是隐语义模型可以挖掘出更深层的物体或者是用户之间的关系,覆盖性会更好,双方各有优缺点。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.09.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 推荐系统
  • 推荐系统的评估方法
    • 准确度
      • 覆盖率
        • 多样性
          • 冷启动
          • 相似度的衡量
          • 推荐算法
            • 基于内容的推荐
              • 基于关联规则的推荐
                • 协同过滤的推荐
                  • 基于知识的推荐
                    • 基于图的推荐
                      • 组合推荐
                        • 基于内容的推荐系统
                          • 协同过滤的推荐
                            • user-based CF
                            • item_based CF
                        • 基于隐语义的推荐
                          • 上面提到的只是最简单的MF模型,但是这类模型有一个缺点,他们分解出来的东西会有负数,这就尴尬了,因为很少有变量因素会其负作用的,于是便出现了非负矩阵分解。
                          • NMF
                            • 代码实现
                              • CF VS隐语义
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档