Skip to content

用户行为数据简介

​ 用户行为数据在网站上最简单的存在形式就是日志。网站在运行过程中都产生大量原始日志(raw log),并将其存储在文件系统中。很多互联网业务会把多种原始日志按照用户行为汇总成会话日志(session log),其中每个 会话表示一次用户行为和对应的服务。

​ 比如,在搜索引擎和搜索广告系统中,服务会为每次查询生成一个展示日志(impression log),其中记录了查询和返回结果。如果用户点击了某个结果,这个点击信息会被服务器截获并存储在点击日志(click log)中。

​ 这些日志记录了用户的各种行为,如在电子商务网站中这些行为主要包括网页浏览、购买、点击、评分和评论等。

​ 用户行为在个性化推荐系统中一般分两种——显性反馈行为(explicit feedback)和隐性反馈行为(implicit feedback)。显性反馈行为包括用户明确表示对物品喜好的行为。这里的主要方式就是评分和喜欢/不喜欢。隐性反馈行为指的是那些不能明确反应用户喜好的行为。最具代表性的隐性反馈行为就是页面浏览行为。用户浏览一个物品的页面并不代表用户一定喜欢这个页面展示的物品,比如可能因为这个页面链接显示在首页,用户更容易点击它而已。相比显性反馈,隐性反馈虽然不明确,但数据量更大。

在很多网站中,很多用户甚至只有隐性反馈数据,而没有显性反馈数据。

显性反馈数据隐性反馈数据
用户兴趣明确不明确
数量较少庞大
存储数据库分布式文件系统
实时读取实时有延迟
正负反馈都有只有正反馈

用户行为分析

在利用用户行为数据设计推荐算法之前,研究人员首先需要对用户行为数据进行分析,了解数据中蕴含的一般规律,这样才能对算法的设计起到指导作用。本节将介绍用户行为数据中蕴含的一般规律,这些规律并不是只存在于一两个网站中的特例,而是存在于很多网站中的普遍规律。

用户活跃度和物品流行度的分布

很多关于互联网数据的研究发现,互联网上的很多数据分布都满足一种称为Power Law 的分布,这个分布在互联网领域也称长尾分布

$$ f(x)=αx^k $$

用户活跃度和物品流行度的关系

一般来说,不活跃的用户要么是新用户,要么是只来过网站一两次的老用户。那么,不同活跃度的用户喜欢的物品的流行度是否有差别?一般认为,新用户倾向于浏览热门的物品,因为他们对网站还不熟悉,只能点击首页的热门物品,而老用户会逐渐开始浏览冷门的物品。

仅仅基于用户行为数据设计的推荐算法一般称为协同过滤算法

学术界对协同过滤算法进行了深入研究,提出了很多方法,比如基于邻域的方法( neighborhood-based )、隐语义模型( latent factor model )、基于图的随机游走算法( random walk on graph )等。在这些方法中,最著名的、在业界得到最广泛应用的算法是基于邻域的方法,而基于邻域的方法主要包含下面两种算法。

  • 基于用户的协同过滤算法 这种算法给用户推荐和他兴趣相似的其他用户喜欢的物品。
  • 基于物品的协同过滤算法 这种算法给用户推荐和他之前喜欢的物品相似的物品。

实验设计和算法评测

评测推荐系统有 3 种方法——离线实验、用户调查和在线实验

实验设计

协同过滤算法的离线实验一般如下设计。

  1. 首先,将用户行为数据集按照均匀分布随机分成 M份(本章取 M =8 ),挑选一份作为测试集,将剩下的 M -1 份作为训练集。

  2. 然后在训练集上建立用户兴趣模型,并在测试集上对用户行为进行预测,统计出相应的评测指标。

  3. 为了保证评测指标并不是过拟合的结果,需要进行 M 次实验,并且每次都使用不同的测试集。

  4. 然后将 M 次实验测出的评测指标的平均值作为最终的评测指标。

python
def SplitData(data, M, k, seed):
    test = []
    train = []
    random.seed(seed)
    for user, item in data:
        if random.randint(0,M) == k:
            test.append([user,item])
        else:
            train.append([user,item])
    return train, test

这里,每次实验选取不同的 k ( 0 ≤ k ≤ M  1 )和相同的随机数种子 seed ,进行 M 次实验就可以得到 M 个不同的训练集和测试集,然后分别进行实验,用 M 次实验的平均值作为最后的评测指标。这样做主要是防止某次实验的结果是过拟合的结果( over fitting ),但如果数据集够大,模型够简单,为了快速通过离线实验初步地选择算法,也可以只进行一次实验。

评测指标

对用户 u 推荐 N 个物品(记为 R ( u ) ),令用户 u 在测试集上喜欢的物品集合为 T ( u ) ,然后可以通过准确率 / 召回率评测推荐算法的精度: $$ Recall = \frac{\sum_{u}\vert R(u) \cap T(u)\vert}{\sum_{u}\vert T(u)\vert} $$

$$ Precision = \frac{\sum_{u}\vert R(u) \cap T(u)\vert}{\sum_{u}\vert R(u)\vert} $$

召回率描述有多少比例的用户 — 物品评分记录包含在最终的推荐列表中,而准确率描述最终的推荐列表中有多少比例是发生过的用户 — 物品评分记录。

python
def Recall(train, test, N):
    hit = 0
    all = 0
    for user in train.keys():
        tu = test[user]
        rank = GetRecommendation(user, N)
        for item, pui in rank:
            if item in tu:
                hit += 1
        all += len(tu)
    return hit / (all * 1.0)


def Precision(train, test, N):
    hit = 0
    all = 0
    for user in train.keys():
        tu = test[user]
        rank = GetRecommendation(user, N)
        for item, pui in rank:
            if item in tu:
                hit += 1
        all += N
    return hit / (all * 1.0)

除了评测推荐算法的精度,本章还计算了算法的覆盖率,覆盖率反映了推荐算法发掘长尾的能力,覆盖率越高,说明推荐算法越能够将长尾中的物品推荐给用户。这里,我们采用最简单的覆盖率定义: $$ Coverage=\frac{\vert\bigcup_{\upsilon\in U}^{R(u)}\vert}{\vert I\vert} $$ 该覆盖率表示最终的推荐列表中包含多大比例的物品。如果所有的物品都被推荐给至少一个用户,那么覆盖率就是 100% 。如下代码可以用来计算推荐算法的覆盖率:

python
def Coverage(train, test, N):
    recommend_items = set()
    all_items = set()
    for user in train.keys():
        for item in train[user].keys():
            all_items.add(item)
        rank = GetRecommendation(user, N)
        for item, pui in rank:
            recommend_items.add(item)
    return len(recommend_items) / (len(all_items) * 1.0)

最后,我们还需要评测推荐的新颖度,这里用推荐列表中物品的平均流行度度量推荐结果的新颖度。如果推荐出的物品都很热门,说明推荐的新颖度较低,否则说明推荐结果比较新颖。

python
def Popularity(train, test, N):
    item_popularity = dict()
    for user, items in train.items():
        for item in items.keys():
            if item not in item_popularity:
                item_popularity[item] = 0
        item_popularity[item] += 1
    ret = 0
    n = 0
    for user in train.keys():
        rank = GetRecommendation(user, N)
        for item, pui in rank:
            ret += math.log(1 + item_popularity[item])
            n += 1
    ret /= n * 1.0
    return ret

这里,在计算平均流行度时对每个物品的流行度取对数,这是因为物品的流行度分布满足长尾分布,在取对数后,流行度的平均值更加稳定。

基于邻域的算法

基于用户的协同过滤算法

​ 基于用户的协同过滤算法是推荐系统中最古老的算法。可以不夸张地说,这个算法的诞生标志了推荐系统的诞生。该算法在 1992 年被提出,并应用于邮件过滤系统, 1994 年被 GroupLens 用于新闻过滤。在此之后直到 2000 年,该算法都是推荐系统领域最著名的算法。

​ 那么,在一个在线个性化推荐系统中,当一个用户 A 需要个性化推荐时,可以先找到和他有相似兴趣的其他用户,然后把那些用户喜欢的、而用户 A 没有听说过的物品推荐给 A 。

从上面的描述中可以看到,基于用户的协同过滤算法主要包括两个步骤。 (1) 找到和目标用户兴趣相似的用户集合。 (2) 找到这个集合中的用户喜欢的,且目标用户没有听说过的物品推荐给目标用户。

步骤 (1) 的关键就是计算两个用户的兴趣相似度。这里,协同过滤算法主要利用行为的相似度计算兴趣的相似度。

给定用户 u 和用户 v ,令 N(u) 表示用户 u 曾经有过正反馈的物品集合,令 N(v)为用户 v 曾经有过正反馈的物品集合。那么,我们可以通过如下的 Jaccard 公式简单地计算 u 和 v 的兴趣相似度: $$ \omega_{\upsilon\nu}=\frac{\vert N(\upsilon) \cap N(\nu)\vert}{\vert N(\upsilon) \cup N(\nu)\vert} $$

或者通过余弦相似度计算: $$ \omega_{\upsilon\nu}=\frac{\vert N(\upsilon) \cap N(\nu)\vert}{\sqrt{\vert N(\upsilon)\vert \vert N(\nu)\vert}} $$

python
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

上面的算法将很多时间浪费在了计算这种用户之间的相似度上。很多用户相互之间并没有对同样的物品产生过行为,即很多时候|N(u)∩N(v)|=0。

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

python
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

得到用户之间的兴趣相似度后, UserCF 算法会给用户推荐和他兴趣最相似的 K 个用户喜欢的物品。如下的公式度量了 UserCF 算法中用户 u 对物品 i 的感兴趣程度 $$ p(u,i)=\sum_{\nu\in S(u,K)\cap N(i)}\omega_{uv}r_{vi} $$ 其中, S(u, K) 包含和用户 u 兴趣最接近的 K 个用户, N(i) 是对物品 i 有过行为的用户集合, w_{uv}是用户 u 和用户 v 的兴趣相似度,r_{vi} 代表用户 v 对物品 i 的兴趣,因为使用的是单一行为的隐反馈数据,所以所有的 r_{vi} =1 。

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

python
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

用户相似度计算的改进

首先,以图书为例,如果两个用户都曾经买过《新华字典》,这丝毫不能说明他们兴趣相似,因为绝大多数中国人小时候都买过《新华字典》。但如果两个用户都买过《数据挖掘导论》,那可以认为他们的兴趣比较相似,因为只有研究数据挖掘的人才会买这本书。换句话说,两个用户对冷门物品采取过同样的行为更能说明他们兴趣的相似度。

因此, John S. Breese 在论文“Empirical Analysis of Predictive Algorithms for Collaborative Filtering”中提出了如下公式,根据用户行为计算用户的兴趣相似度: $$ w_{uv}=\frac{\sum_{i\in N(u)\cap N(v)}\frac{1}{\log{1+\vert N(i)\vert}}}{\sqrt{\vert N(u)\vert \vert N(v)\vert}} $$ 可以看到,该公式惩罚了用户 u 和用户 v 共同兴趣列表中热门物品对他们相似度的影响。

python
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

基于物品的协同过滤算法

基于物品的协同过滤( item-based collaborative filtering )算法是目前业界应用最多的算法。无论是亚马逊网,还是 Netflix 、 Hulu 、 YouTube ,其推荐算法的基础都是该算法。

基于用户的协同过滤算法在一些网站(如 Digg )中得到了应用,但该算法有一些缺点。首先,随着网站的用户数目越来越大,计算用户兴趣相似度矩阵将越来越困难,其运算时间复杂度和空间复杂度的增长和用户数的增长近似于平方关系。其次,基于用户的协同过滤很难对推荐结果作出解释。因此,著名的电子商务公司亚马逊提出了另一个算法——基于物品的协同过滤算法。

基于物品的协同过滤算法(简称 ItemCF )给用户推荐那些和他们之前喜欢的物品相似的物品。比如,该算法会因为你购买过《数据挖掘导论》而给你推荐《机器学习》。不过, ItemCF 算法并不利用物品的内容属性计算物品之间的相似度,它主要通过分析用户的行为记录计算物品之间的相似度。该算法认为,物品 A 和物品 B 具有很大的相似度是因为喜欢物品 A 的用户大都也喜欢物品 B 。基于物品的协同过滤算法可以利用用户的历史行为给推荐结果提供推荐解释,比如给用户推荐《机器学习》的解释可以是因为用户之前喜欢《数据挖掘导论》。

基于物品的协同过滤算法主要分为两步。 (1) 计算物品之间的相似度。 (2) 根据物品的相似度和用户的历史行为给用户生成推荐列表。

我们可以用下面的公式定义物品的相似度: $$ w_{ij}=\frac{\vert N(i) \cap N(j)\vert}{\vert N(i)\vert} $$ 这里,分母 |N(i)| 是喜欢物品 i 的用户数,而分子|N(i)∩N(j)|是同时喜欢物品 i 和物品 j 的用户数。因此,上述公式可以理解为喜欢物品 i 的用户中有多少比例的用户也喜欢物品 j 。

上述公式虽然看起来很有道理,但是却存在一个问题。如果物品 j 很热门,很多人都喜欢,那么 W ij 就会很大,接近 1 。因此,该公式会造成任何物品都会和热门的物品有很大的相似度,这对于致力于挖掘长尾信息的推荐系统来说显然不是一个好的特性。为了避免推荐出热门的物品,可以用下面的公式: $$ w_{ij}=\frac{\vert N(i) \cap N(j)\vert}{\sqrt{\vert N(i)\vert \vert N(j)\vert}} $$ 这个公式惩罚了物品 j 的权重,因此减轻了热门物品会和很多物品相似的可能性。

从上面的定义可以看到,在协同过滤中两个物品产生相似度是因为它们共同被很多用户喜欢,也就是说每个用户都可以通过他们的历史兴趣列表给物品“贡献”相似度。

这里面蕴涵着一个假设,就是每个用户的兴趣都局限在某几个方面,因此如果两个物品属于一个用户的兴趣列表,那么这两个物品可能就属于有限的几个领域,而如果两个物品属于很多用户的兴趣列表,那么它们就可能属于同一个领域,因而有很大的相似度。

和 UserCF 算法类似,用 ItemCF 算法计算物品相似度时也可以首先建立用户 — 物品倒排表(即对每个用户建立一个包含他喜欢的物品的列表),然后对于每个用户,将他物品列表中的物品两两在共现矩阵 C 中加 1 。

python
def ItemSimilarity(train):
    #calculate co-rated users between items
    C = dict()
    N = dict()
    for u, items in train.items():
        for i in users:
            N[i] += 1
            for j in users:
                if i == j:
                    continue
                C[i][j] += 1
    #calculate finial similarity matrix W
    W = dict()
    for i,related_items in C.items():
        for j, cij in related_items.items():
            W[u][v] = cij / math.sqrt(N[i] * N[j])
    return W

在得到物品之间的相似度后,ItemCF通过如下公式计算用户u对一个物品j的兴趣: $$ p_{uj}=\sum_{i\in S(j,K)\cap N(u)}\omega_{ji}r_{ui} $$ 这里N(u)是用户喜欢的物品的集合,S(j,K)是和物品j最相似的K个物品的集合,w ji 是物品j和i的相似度,r ui 是用户u对物品i的兴趣。(对于隐反馈数据集,如果用户u对物品i有过行为,即可令r ui =1。)该公式的含义是,和用户历史上感兴趣的物品越相似的物品,越有可能在用户的推荐列表中获得比较高的排名。该公式的实现代码如下所示。

python
def Recommendation(train, user_id, W, K):
    rank = dict()
    ru = train[user_id]
    for i,pi in ru.items():
        for j, wj in sorted(W[i].items(),key=itemgetter(1), reverse=True)[0:K]:
            if j in ru:
                continue
            rank[j] += pi * wj
    return rank

ItemCF 的一个优势就是可以提供推荐解释,即利用用户历史上喜欢的物品为现在的推荐结果进行解释。如下代码实现了带解释的 ItemCF 算法:

python
def Recommendation(train, user_id, W, K):
    rank = dict()
    ru = train[user_id]
    for i,pi in ru.items():
        for j, wj in sorted(W[i].items(), /
            key=itemgetter(1), reverse=True)[0:K]:
                if j in ru:
                    continue
                rank[j].weight += pi * wj
                rank[j].reason[i] = pi * wj
    return rank

用户活跃度对物品相似度的影响

​ 假设有这么一个用户,他是开书店的,并且买了当当网上 80% 的书准备用来自己卖。那么,他的购物车里包含当当网 80% 的书。假设当当网有 100 万本书,也就是说他买了 80 万本。从前面对 ItemCF 的讨论可以看到,这意味着因为存在这么一个用户,有 80 万本书两两之间就产生了相似度,也就是说,内存里即将诞生一个 80 万乘 80 万的稠密矩阵。

​ 另外可以看到,这个用户虽然活跃,但是买这些书并非都是出于自身的兴趣,而且这些书覆盖了当当网图书的很多领域,所以这个用户对于他所购买书的两两相似度的贡献应该远远小于一个只买了十几本自己喜欢的书的文学青年

​ 上文提到,John S. Breese 在论文中提出了一个称为 IUF ( Inverse User Frequence ),即用户活跃度对数的倒数的参数,他也认为活跃用户对物品相似度的贡献应该小于不活跃的用户,他提出应该增加 IUF参数来修正物品相似度的计算公式: $$ w_{uv}=\frac{\sum_{i\in N(u)\cap N(v)}\frac{1}{\log{1+\vert N(i)\vert}}}{\sqrt{\vert N(u)\vert \vert N(v)\vert}} $$ ​ 当然,上面的公式只是对活跃用户做了一种软性的惩罚,但对于很多过于活跃的用户,比如上面那位买了当当网 80% 图书的用户,为了避免相似度矩阵过于稠密,我们在实际计算中一般直接忽略他的兴趣列表,而不将其纳入到相似度计算的数据集中。

python
def ItemSimilarity(train):
    #calculate co-rated users between items
    C = dict()
    N = dict()
    for u, items in train.items():
        for i in users:
            N[i] += 1
            for j in users:
                if i == j:
                    continue
                C[i][j] += 1 / math.log(1 + len(items) * 1.0)
        #calculate finial similarity matrix W
        W = dict()
        for i,related_items in C.items():
            for j, cij in related_items.items():
                W[u][v] = cij / math.sqrt(N[i] * N[j])
    return W

上面的算法记为 ItemCF-IUF。

物品相似度的归一化

​ Karypis 在研究中发现如果将 ItemCF 的相似度矩阵按最大值归一化,可以提高推荐的准确率。其研究表明,如果已经得到了物品相似度矩阵 w ,那么可以用如下公式得到归一化之后的相似度矩阵 w' : $$ x'{ij}=\frac{w{ij}}{max_{j}w_{ij}} $$ ​ 其实,归一化的好处不仅仅在于增加推荐的准确度,它还可以提高推荐的覆盖率和多样性。一般来说,物品总是属于很多不同的类,每一类中的物品联系比较紧密。

​ 假设物品分为两类—— A 和 B , A 类物品之间的相似度为 0.5 , B 类物品之间的相似度为 0.6 ,而 A 类物品和 B 类物品之间的相似度是 0.2 。在这种情况下,如果一个用户喜欢了 5 个 A 类物品和 5 个 B 类物品,用 ItemCF 给他进行推荐,推荐的就都是 B 类物品,因为 B 类物品之间的相似度大。但如果归一化之后, A 类物品之间的相似度变成了 1 , B 类物品之间的相似度也是 1 ,那么这种情况下,用户如果喜欢 5 个 A 类物品和 5 个 B 类物品,那么他的推荐列表中 A 类物品和 B 类物品的数目也应该是大致相等的。从这个例子可以看出,相似度的归一化可以提高推荐的多样性。

​ 那么,对于两个不同的类,什么样的类其类内物品之间的相似度高,什么样的类其类内物品相似度低呢?一般来说,热门的类其类内物品相似度一般比较大。如果不进行归一化,就会推荐比较热门的类里面的物品,而这些物品也是比较热门的。因此,推荐的覆盖率就比较低。相反,如果进行相似度的归一化,则可以提高推荐系统的覆盖率。

UserCF和ItemCF的综合比较

​ 首先回顾一下 UserCF 算法和 ItemCF 算法的推荐原理。 UserCF 给用户推荐那些和他有共同兴趣爱好的用户喜欢的物品,而 ItemCF 给用户推荐那些和他之前喜欢的物品类似的物品。从这个算法的原理可以看到, UserCF 的推荐结果着重于反映和用户兴趣相似的小群体的热点,而 ItemCF的推荐结果着重于维系用户的历史兴趣。换句话说, UserCF 的推荐更社会化,反映了用户所在的小型兴趣群体中物品的热门程度,而 ItemCF 的推荐更加个性化,反映了用户自己的兴趣传承。

​ 在新闻网站中,用户的兴趣不是特别细化,绝大多数用户都喜欢看热门的新闻。即使是个性化,也是比较粗粒度的,比如有些用户喜欢体育新闻,有些喜欢社会新闻,而特别细粒度的个性化一般是不存在的。比方说,很少有用户只看某个话题的新闻,主要是因为这个话题不可能保证每天都有新的消息,而这个用户却是每天都要看新闻的。因此,个性化新闻推荐更加强调抓住新闻热点,热门程度和时效性是个性化新闻推荐的重点,而个性化相对于这两点略显次要。因此, UserCF 可以给用户推荐和他有相似爱好的一群其他用户今天都在看的新闻,这样在抓住热点和时效性的同时,保证了一定程度的个性化。

​ UserCF 适合用于新闻推荐的另一个原因是从技术角度考量的。因为作为一种物品,新闻的更新非常快,每时每刻都有新内容出现,而 ItemCF 需要维护一张物品相关度的表,如果物品更新很快,那么这张表也需要很快更新,这在技术上很难实现。绝大多数物品相关度表都只能做到一天一次更新,这在新闻领域是不可以接受的。而 UserCF 只需要用户相似性表,虽然 UserCF 对于新用户也需要更新相似度表,但在新闻网站中,物品的更新速度远远快于新用户的加入速度,而且对于新用户,完全可以给他推荐最热门的新闻,因此 UserCF 显然是利大于弊。

​ 但是,在图书、电子商务和电影网站,比如亚马逊、豆瓣、 Netflix 中, ItemCF 则能极大地发挥优势。首先,在这些网站中,用户的兴趣是比较固定和持久的。一个技术人员可能都是在购买技术方面的书,而且他们对书的热门程度并不是那么敏感,事实上越是资深的技术人员,他们看的书就越可能不热门。

​ 此外,这些系统中的用户大都不太需要流行度来辅助他们判断一个物品的好坏,而是可以通过自己熟悉领域的知识自己判断物品的质量。因此,这些网站中个性化推荐的任务是帮助用户发现和他研究领域相关的物品。因此, ItemCF 算法成为了这些网站的首选算法。此外,这些网站的物品更新速度不会特别快,一天一次更新物品相似度矩阵对它们来说不会造成太大的损失,是可以接受的。

​ 同时,从技术上考虑, UserCF 需要维护一个用户相似度的矩阵,而 ItemCF 需要维护一个物品相似度矩阵。从存储的角度说,如果用户很多,那么维护用户兴趣相似度矩阵需要很大的空间,同理,如果物品很多,那么维护物品相似度矩阵代价较大。

​ 在早期的研究中,大部分研究人员都是让少量的用户对大量的物品进行评价,然后研究用户兴趣的模式。那么,对于他们来说,因为用户很少,计算用户兴趣相似度是最快也是最简单的方法。但在实际的互联网中,用户数目往往非常庞大,而在图书、电子商务网站中,物品的数目则是比较少的。此外,物品的相似度相对于用户的兴趣一般比较稳定,因此使用 ItemCF 是比较好的选择。当然,新闻网站是个例外,在那儿,物品的相似度变化很快,物品数目庞大,相反用户兴趣则相对固定(都是喜欢看热门的),所以新闻网站的个性化推荐使用 UserCF 算法的更多。

UserCFItemCF
性能适用于用户较少的场合,如果用户很多,计算用户相似度矩阵代价很大适用于物品数明显小于用户数的场合,如果物品很多(网页),计算物品相似度矩阵代价很大
领域时效性较强,用户个性化兴趣不太明显的领域长尾物品丰富,用户个性化需求强烈的领域
实时性用户有新行为,不一定造成推荐结果的立即变化用户有新行为,一定会导致推荐结果的实时变化
冷启动在新用户对很少的物品产生行为后,不能立即对他进行个性化推荐,因为用户相似度表是每隔一段时间离线计算的
新物品上线后一段时间,一旦有用户对物品产生行为,就可以将新物品推荐给和对它产生行为的用户兴趣相似的其他用户
新用户只要对一个物品产生行为,就可以给他推荐和该物品相关的其他物品
但没有办法在不离线更新物品相似度表的情况下将新物品推荐给用户
推荐理由很难提供令用户信服的推荐解释利用用户的历史行为给用户做推荐解释,可以令用户比较信服