UCF,基于用户的协同过滤算法

基础算法

1992 年提出UCF,UCF 的两个步骤

  1. 找到和目标用户相似的用户集合
  2. 找到这个集合中用户喜欢的,且用户未见过的物品推荐

如何计算两个用户 u,vu,v 的兴趣相似度?

  • N(u)N(u) 表示用户 uu 曾经有过正反馈的物品集合
  • N(v)N(v) 表示用户 vv 曾经有过正反馈的物品集合

利用 Jaccard 公式(余弦也行)计算用户 u,vu,v 的兴趣相似度 wuv

余弦相似度,重点

 [ 用户行为记录举例 ]

用户 AA 对物品 a,b,da,b,d 有过正反馈,用户 BB 对物品 a,ca,c 有过正反馈,利用余弦相似度计算得出

同理可以计算出用户 AA 和 用户 C,DC,D 的相似度

我们可以撸一遍余弦相似度计算的代码,反正就是两个 for 循环

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) # 这里 N(u) x N(v) 就是 len(u) x len(v)

    return W

[ 用户-物品倒排表 ]

如何快速计算两个用户 u,vu,v 的兴趣相似度?

难点

参考这里,计算时间复杂度为 O(|U|2)。事实上很多用户并没有对同一物品产生过反馈,即 |N(u)∩N(v)|=0。如果计算这种用户的相似度(肯定为 0),无疑是浪费了时间。怎么办呢?

解决思路是,先计算出|N(u)∩N(v)|≠0的用户 pair(u,v),然后再对这种情况除以分母 √|N(u)||N(v)|。

首先,建立 item→useritem→user 的倒排表,建立物品和反馈用户列表之间的关系。

然后考虑,建立用户稀疏矩阵,大小为 用户数 ×× 用户数

C[u][v]=|N(u)∩N(v)|

假设用户 u 和 用户 v 同时反馈过 K 个物品,就有 C[u][v]=K。

好了,这里我们扫描刚刚建立好的倒排表的用户列表,将这个列表中的两两用户u,v对应的 C[u][v]加 1。最终就可以得到用户之间不为 0 的 C[u][v]。

比之,之前的方法,这里我们这里有两点变化:第一,遍历 item,这个长,但是只有一遍;第二,针对item→user 的 user_list 两两(u,v)+1,这个需要遍历两遍,但是很短

最后,在第二步我们建立了余弦距离的分子C[u][v],计算的时候,拿出分母 √|N(u)||N(v)| 即可,N(u)的定义是用户反馈的 item 集合, 相对容易计算。

改进之后的代码

def UserSimilarity(train):
    # 建立 item -> users 倒排表
    item_users = dict()
    for u, item in train.items():
        for i in item.keys():
            if i not in item_users:
                item_users[i] = set()

            item_users[i].add(u)  # 这里可以用 defaultdict 替换

    # 计算分子项,即 $ C[u][v]=|N(u) \cap N(v)| $
    C = dict()  # 用户 u, v 矩阵
    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

    # 计算相似度矩阵 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

如何度量 UCF 算法中,用户 u 对物品 i的兴趣程度?

  • S(u,K) 和用户 u兴趣最接近的 K 个用户的集合
  • N(i) 对物品 i 有过反馈的用户集合
  • wuv 是用户 u,v 的兴趣相似度
  • rvi 用户 v 对物品 i 的兴趣,默认为 1

这里计算的方式就是,先找到用户uu的 Top K 的好基友,问问这些基友有没有买过 N(i)(比如 airpods)。基友们对新款 airpods 的评分是 rvi,我们再把用户u对各个基友v的人品评价记作 wuv,作为权重。最后一步,把 权重× 评价 就是最后的评分。到底买不买,就看这个评分了!

def Recommand(user, train, w):
    rank = dict()
    interacted_items = train[user]

    for v, wuv in sorted(W[u].items, key=itemgetter(1), reverse=True)[0:K]: # 找打了用户 u 的 K 个基友
        for i, rvi in train[v].items: # K 个基友最近看了什么
            if i in interacted_items: # 过滤用户见过的物品,反馈过的
                continue

            rank[i] += wuv*rvi # 上面讲的打分函数,对物品 i 打分

    return rank

这里 K 是超参数,评价指标为准确率,召回率,覆盖率,流行度。

  • 准确率和召回率对 K 不是很敏感
  • K越大,流行度上越趋近于全局热门物品
  • K越大,覆盖率越低

用户相似度的改进

根据用户行为计算用户的兴趣相似度,惩罚用户u和用户v共同兴趣列表中的热门物品

注意这里分子的变化

惩罚了每一个共同兴趣,我们把改进后的算法叫做User-IIFF算法

我们再撸一遍代码

def UserSimilarity(train):
    # 建立倒排表
    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)

    # 计算分子项
    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))

    # 计算相似度矩阵
    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

实验证明 UserCF-IIF 在各项性能上略优于 UserCF。

参考资料:推荐系统实践,项亮,第二章

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值