推荐系统实践--基于用户的协同过滤算法

基于邻域的算法是推荐系统中最基本的算法,该算法不只在学术界获得了深刻研究,并且在业界获得了普遍应用。基于邻域的算法分为两大类,一类是基于用户的协同过滤算法,另外一类是基于物品的协同过滤算法。算法

咱们先来看看基于用户的协同过滤算法,基于物品的协同过滤算法大致思路和基于用户的差很少,能够本身参考对比学习。学习

基于用户的协同过滤算法

每一年新学期开始,刚进实验室的师弟总会问师兄类似的问题,好比“我应该买什么专业书啊”、“我应该看什么论文啊”等。这个时候,师兄通常会给他们作出一些推荐。这就是现实中个性化推荐的一种例子。在这个例子中,师弟可能会请教不少师兄,而后作出最终的判断。师弟之因此请教师兄,一方面是由于他们有社会关系,互相认识且信任对方,但更主要的缘由是师兄和师弟有共同的研究领域和兴趣。那么,在一个在线个性化推荐系统中,当一个用户A须要个性化推荐时,能够先找到和他有类似兴趣的其余用户,而后把那些用户喜欢的、而用户A没有据说过的物品推荐给A。这种方法称为基于用户的协同过滤算法。ui

基于用户的协同过滤算法主要包括两个步骤。spa

(1) 找到和目标用户兴趣类似的用户集合。code

(2) 找到这个集合中的用户喜欢的,且目标用户没有据说过的物品推荐给目标用户。blog

步骤(1)的关键就是计算两个用户的兴趣类似度。这里,协同过滤算法主要利用行为的类似度计算兴趣的类似度。给定用户u和用户v,令N(u)表示用户u曾经有过正反馈的物品集合,令N(v)为用户v曾经有过正反馈的物品集合。那么,咱们能够经过以下的Jaccard公式简单地计算u和v的兴趣类似度或者经过余弦公式:get

      jaccard                                                                             余项公式:it

                         数据挖掘

 

 

这个一个行为记录                                             咱们能够根据余弦公式计算以下table

                             

以余弦类似度为例,实现该类似度能够利用下面的伪代码:

def UserSimilarity(train):
    W = dict()
    for u in train.keys():
        for v in train.keys():
            if u == v:
                continue
            W[u][v] = len(train[u] & train[v])
            W[u][v] = /= math.sqrt(len(train[u]) * len(train[v]) * 1.0)
    return W

这种方法的时间复杂度是O(|U|*|U|),这在用户数很大时很是耗时。事实上,不少用户相互之间并无对一样的物品产生过行为,即不少时候N(u)^ N(v) = 0。上面的算法将不少时间浪费在了计算这种用户之间的类似度上。若是换一个思路,咱们能够首先计算出N(u)^ N(v) != 0 的用户对(u,v),而后再对这种状况除以分母sqrt(N(u)*N(v)) 。

为此,能够首先创建物品到用户的倒排表,对于每一个物品都保存对该物品产生过行为的用户列表。令稀疏矩阵C[u][v]= N(u)^ N(v) 。那么,假设用户u和用户v同时属于倒排表中K个物品对应的用户列表,就有C[u][v]=K。从而,能够扫描倒排表中每一个物品对应的用户列表,将用户列表中的两两用户对应的C[u][v]加1,最终就能够获得全部用户之间不为0的C[u][v]

def UserSimilarity(train):
    # build inverse table for item_users
    item_users = dict()
    for u, items in train.items():
        for i in items.keys():
            if i not in item_users:
                item_users[i] = set()
            item_users[i].add(u)
    #calculate co-rated items between users
    C = dict()
    N = dict()
    for i, users in item_users.items():
        for u in users:
            N[u] += 1
            for v in users:
                if u == v:
                    continue
                C[u][v] += 1
    #calculate finial similarity matrix W
    W = dict()
    for u, related_users in C.items():
        for v, cuv in related_users.items():
            W[u][v] = cuv / math.sqrt(N[u] * N[v])
    return W

 

下面是按照想法创建的稀疏矩阵,对于物品a,将W[A][B]和W[B][A]加1,对于物品b,将W[A][C]和W[C][A]加1,以此类推,扫描完全部物品后,咱们能够获得最终的W矩阵,这里的W是余弦类似度中的分子部分,而后将W除以分母能够获得最终的用户兴趣类似度

获得用户之间的兴趣类似度后,UserCF算法会给用户推荐和他兴趣最类似的K个用户喜欢的物品。上面右边公式度量了UserCF算法中用户u对物品i的感兴趣程度:其中,S(u, K)包含和用户u兴趣最接近的K个用户,N(i)是对物品i有过行为的用户集合,Wuv是用户u和用户v的兴趣类似度,Rvi表明用户v对物品i的兴趣,由于使用的是单一行为的隐反馈数据,因此全部的Rvi=1。

以下代码实现了上面的UserCF推荐算法:

def Recommend(user, train, W):
    rank = dict()
    interacted_items = train[user]
    for v, wuv in sorted(W[u].items, key=itemgetter(1), reverse=True)[0:K]:
        for i, rvi in train[v].items:
        if i in interacted_items:
            #we should filter items user interacted before
            continue
        rank[i] += wuv * rvi
    return rank

选取K=3,用户A对物品c、e没有过行为,所以能够把这两个物品推荐给用户A。根据UserCF算法,用户A对物品c、e的兴趣是:

用户类似度计算的改进

若是两个用户都曾经买过《新华字典》,这丝绝不能说明他们兴趣类似,由于绝大多数中国人小时候都买过《新华字典》。但若是两个用户都买过《数据挖掘导论》,那能够认为他们的兴趣比较类似,由于只有研究数据挖掘的人才会买这本书。换句话说,两个用户对冷门物品采起过一样的行为更能说明他们兴趣的类似度。所以,John S. Breese在论文①中提出了以下公式,根据用户行为计算用户的兴趣类似度:

分子中的倒数惩罚了用户u和用户v共同兴趣列表中热门物品对他们类似度的影响。N(i)是对物品i有过行为的用户集合,越热门,N(i)越大

def UserSimilarity(train):
    # build inverse table for item_users
    item_users = dict()
    for u, items in train.items():
        for i in items.keys():
            if i not in item_users:
                item_users[i] = set()
            item_users[i].add(u)
    #calculate co-rated items between users
    C = dict()
    N = dict()
    for i, users in item_users.items():
        for u in users:
            N[u] += 1
            for v in users:
                if u == v:
                    continue
            C[u][v] += 1 / math.log(1 + len(users))
    #calculate finial similarity matrix W
    W = dict()
    for u, related_users in C.items():
        for v, cuv in related_users.items():
            W[u][v] = cuv / math.sqrt(N[u] * N[v])
    return W
相关文章
相关标签/搜索