推荐系统(二):协同过滤

协同过滤

协同过滤算法是诞生最早,最为基础的推荐算法。该算法是通过对用户的历史浏览以及历史评分等信息通过计算相似度来发现用户对于某一类项目的偏好的算法。
目前应用比较广泛的协同过滤算法是基于邻域的方法, 而这种方法主要有下面两种算法:
基于用户的协同过滤算法(UserCF): 给用户推荐和他兴趣相似的其他用户喜欢的产品
基于物品的协同过滤算法(ItemCF): 给用户推荐和他之前喜欢的物品相似的物品
不管是UserCF还是ItemCF算法, 非常重要的步骤之一就是计算用户和用户或者物品和物品之间的相似度, 所以下面先整理常用的相似性度量方法, 然后再对每个算法的具体细节进行展开。

寻找相似的用户或者项目

现在考虑一种最简单的情况,5个用户都购买了两种商品,然后并对商品进行打分,如下图:
推荐系统(二):协同过滤_第1张图片
以上评分可以作为分类的依据,比如K-means聚类算法,协同过滤算法其实就是通过用户或者项目的历史评分对相似的用户或者项目进行聚类,聚类完成后再通过相关距离的计算来推荐相似的用户或者项目曾经进行的或者历史记录中的项目或者用户。
推荐系统(二):协同过滤_第2张图片
如上图所示我们在为用户A推荐项目时一般都是为其分配用户D或者用户C曾经购买过或者收藏的项目。这就是因为用户A,D, C三人在对于共同购买过的东西具有较为相似的看法。

相关系数度量

杰卡德相似性度量

该部分引用了如下的这篇博客:

https://www.cnblogs.com/chaosimple/p/3160839.html

(1)杰卡德相似系数

两个集合A和B交集元素的个数在A、B并集中所占的比例,称为这两个集合的杰卡德系数,用符号 J(A,B) 表示。杰卡德相似系数是衡量两个集合相似度的一种指标(余弦距离也可以用来衡量两个集合的相似度)。在这里插入图片描述

(2)杰卡德距离

与杰卡德相似系数相反的概念是杰卡德距离(Jaccard Distance),可以用如下公式来表示:
推荐系统(二):协同过滤_第3张图片
杰卡德距离用两个两个集合中不同元素占所有元素的比例来衡量两个集合的区分度。

(3)杰卡德相似系数的应用

假设样本A和样本B是两个n维向量,而且所有维度的取值都是0或1。例如,A(0,1,1,0)和B(1,0,1,1)。我们将样本看成一个集合,1表示集合包含该元素,0表示集合不包含该元素。

p:样本A与B都是1的维度的个数

q:样本A是1而B是0的维度的个数

r:样本A是0而B是1的维度的个数

s:样本A与B都是0的维度的个数

那么样本A与B的杰卡德相似系数可以表示为:
推荐系统(二):协同过滤_第4张图片
此处分母之所以不加s的原因在于:

对于杰卡德相似系数或杰卡德距离来说,它处理的都是非对称二元变量。非对称的意思是指状态的两个输出不是同等重要的,例如,疾病检查的阳性和阴性结果。

按照惯例,我们将比较重要的输出结果,通常也是出现几率较小的结果编码为1(例如HIV阳性),而将另一种结果编码为0(例如HIV阴性)。给定两个非对称二元变量,两个都取1的情况(正匹配)认为比两个都取0的情况(负匹配)更有意义。负匹配的数量s认为是不重要的,因此在计算时忽略。

(4)杰卡德相似度算法分析

杰卡德相似度算法没有考虑向量中潜在数值的大小,而是简单的处理为0和1,不过,做了这样的处理之后,杰卡德方法的计算效率肯定是比较高的,毕竟只需要做集合操作。

余弦相似性度量

余弦相似系数

几何中夹角余弦可用来衡量两个向量方向的差异,机器学习中借用这一概念来衡量样本向量之间的差异。余弦相似度衡量了两个向量的夹角,夹角越小越相似。首先从集合的角度描述余弦相似度,相比于Jaccard公式来说就是分母有差异,不是两个用户交互商品的并集的数量,而是两个用户分别交互的商品数量的乘积。

对于向量a,b其计算公式如下:
推荐系统(二):协同过滤_第5张图片
扩展,如果向量a和b不是二维而是n维,上述余弦的计算法仍然正确。假定a和b是两个n维向量,a是 ,b是 ,则a与b的夹角 的余弦等于:推荐系统(二):协同过滤_第6张图片
余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,夹角等于0,即两个向量相等,这就叫"余弦相似性"。

上述用户-商品交互矩阵在现实情况下是非常的稀疏了,为了避免存储这么大的稀疏矩阵,在计算用户相似度的时候一般会采用集合的方式进行计算。理论上向量之间的相似度计算公式都可以用来计算用户之间的相似度,但是会根据实际的情况选择不同的用户相似度度量方法。

这个在具体实现的时候, 可以使用cosine_similarity进行实现:

from sklearn.metrics.pairwise import cosine_similarity
i = [1, 0, 0, 0]
j = [1, 0.5, 0.5, 0]
consine_similarity([a, b])

皮尔逊相关系数

https://mp.weixin.qq.com/s/oJmlAteSKbcMEUUycK6lTQ

除了用欧氏距离来衡量,皮尔逊相关度是另一种计算用户间关系的方法。现在考虑下面这一种更加复杂、也更加接近真实场景的数据:推荐系统(二):协同过滤_第7张图片

其实呢?皮尔逊相关系数其实就是两个变量之间的协方差和标准差的比值:
在这里插入图片描述
当然也可以换个不同的写法也就是:
推荐系统(二):协同过滤_第8张图片
对于这个,并不陌生。皮尔逊相关系数在-1到1之间。0表示不相关,1表示极强正相关,-1表示极强负相关。
现在来简单计算一下上面例子中,用户A与用户B之间的皮尔逊相关系数。推荐系统(二):协同过滤_第9张图片
剩下的Pearson相关系数如下:

推荐系统(二):协同过滤_第10张图片
皮尔逊相关系数通过使用用户的平均分对各独立评分进行修正,减小了用户评分偏置的影响。具体实现, 我们也是可以调包, 这个计算方式很多, 下面是其中的一种:
`from scipy.stats import pearsonr

i = [1, 0, 0, 0]
j = [1, 0.5, 0.5, 0]
pearsonr(i, j)`

基于用户的协同过滤

基于用户的协同过滤(以下用UserCF表示),思想其实比较简单,当一个用户A需要个性化推荐的时候, 我们可以先找到和他有相似兴趣的其他用户, 然后把那些用户喜欢的, 而用户A没有听说过的物品推荐给A。
推荐系统(二):协同过滤_第11张图片
UserCF算法主要包括两个步骤:

找到和目标用户兴趣相似的集合
找到这个集合中的用户喜欢的, 且目标用户没有听说过的物品推荐给目标用户。

上面的两个步骤中, 第一个步骤里面, 我们会基于前面给出的相似性度量的方法找出与目标用户兴趣相似的用户, 而第二个步骤里面, 如何基于相似用户喜欢的物品来对目标用户进行推荐呢? 这个要依赖于目标用户对相似用户喜欢的物品的一个喜好程度, 那么如何衡量这个程度大小呢? 为了更好理解上面的两个步骤, 下面拿一个具体的例子把两个步骤具体化。
推荐系统(二):协同过滤_第12张图片
给用户推荐物品的过程可以形象化为一个猜测用户对商品进行打分的任务,上面表格里面是5个用户对于5件物品的一个打分情况,就可以理解为用户对物品的喜欢程度。
应用UserCF算法的两个步骤:
首先根据前面的这些打分情况(或者说已有的用户向量)计算一下Alice和用户1, 2, 3, 4的相似程度, 找出与Alice最相似的n个用户。
根据这n个用户对物品5的评分情况和与Alice的相似程度会猜测出Alice对物品5的评分, 如果评分比较高的话, 就把物品5推荐给用户Alice, 否则不推荐。

关于第一个步骤, 上面已经给出了计算两个用户相似性的方法, 这里不再过多赘述, 这里主要解决第二个问题, 如何产生最终结果的预测。

最终结果的预测

根据上面的几种方法, 我们可以计算出向量之间的相似程度, 也就是可以计算出Alice和其他用户的相近程度, 这时候我们就可以选出与Alice最相近的前n个用户, 基于他们对物品5的评价猜测出Alice的打分值, 那么是怎么计算的呢?

假设我们为用户C推荐商品,先检查相似度列表,发现用户C和D、E的pearson系数较高。所以认为这三个用户有相同的偏好,所以对C推荐D和E买过的商品。但是不能推荐商品1~5,因为这些用户C已经买过了。
现在我们找到了用户D和E买过的其他的商品A,B,C,D,E,F。然后让用户D和E与用户C的相似度作为权重 ,计算他们给这些商品打分的加权分数。然后给C按照加权分数从高到低进行推荐。
在这里插入图片描述
在获得用户u对不同物品的评价预测后, 最终的推荐列表根据预测评分进行排序得到。 至此,基于用户的协同过滤算法的推荐过程完成。

根据上面的问题, 下面手算一下:

Aim: 猜测Alice对物品5的得分:
推荐系统(二):协同过滤_第13张图片
这里我们使用皮尔逊相关系数, 也就是Alice与用户1的相似度是0.85。同样的方式, 我们就可以计算与其他用户的相似度, 这里可以使用numpy的相似度函数得到用户的相似性矩阵:

<div align=center>
<img src="https://uploader.shimo.im/f/WJkjP2fHH27Rajrj.png!thumbnail" alt="图片" style="zoom:90%;" />
</div> 

 从这里看出, Alice用户和用户2,用户3,用户4的相似度是0.70, -0.79。 所以如果n=2, 找到与Alice最相近的两个用户是用户1, 和Alice的相似度是0.85, 用户2, 和Alice相似度是0.7

根据相似度用户计算Alice对物品5的最终得分 用户1对物品5的评分是3, 用户2对物品5的打分是5, 那么根据上面的计算公式, 可以计算出Alice对物品5的最终得分。
根据用户评分对用户进行推荐 这时候, 我们就得到了Alice对物品5的得分是4.87, 根据Alice的打分对物品排个序从大到小: 物 品 1 > 物 品 5 > 物 品 3 = 物 品 4 > 物 品 2 物品1>物品5>物品3=物品4>物品2 1>5>3=4>2 这时候,如果要向Alice推荐2款产品的话, 我们就可以推荐物品1和物品5给Alice。

UserCF编程实现

这里简单的通过编程实现上面的案例,为后面的大作业做一个热身, 梳理一下上面的过程其实就是三步: 计算用户相似性矩阵、得到前n个相似用户、计算最终得分。

所以我们下面的程序也是分为这三步:

1. 首先, 先把数据表给建立起来 这里我采用了字典的方式, 之所以没有用pandas, 是因为上面举得这个例子其实是个个例, 在真实情况中, 我们知道, 用户对物品的打分情况并不会这么完整, 会存在大量的空值, 所以矩阵会很稀疏, 这时候用DataFrame, 会有大量的NaN。故这里用字典的形式存储。 用两个字典, 第一个字典是物品-用户的评分映射, 键是物品1-5, 用A-E来表示, 每一个值又是一个字典, 表示的是每个用户对该物品的打分。 第二个字典是用户-物品的评分映射, 键是上面的五个用户, 用1-5表示, 值是该用户对每个物品的打分。

# 定义数据集, 也就是那个表格, 注意这里我们采用字典存放数据, 因为实际情况中数据是非常稀疏的, 很少有情况是现在这样
def loadData():
    items={
     'A': {
     1: 5, 2: 3, 3: 4, 4: 3, 5: 1},
           'B': {
     1: 3, 2: 1, 3: 3, 4: 3, 5: 5},
           'C': {
     1: 4, 2: 2, 3: 4, 4: 1, 5: 5},
           'D': {
     1: 4, 2: 3, 3: 3, 4: 5, 5: 2},
           'E': {
     2: 3, 3: 5, 4: 4, 5: 1}
          }
    users={
     1: {
     'A': 5, 'B': 3, 'C': 4, 'D': 4},
           2: {
     'A': 3, 'B': 1, 'C': 2, 'D': 3, 'E': 3},
           3: {
     'A': 4, 'B': 3, 'C': 4, 'D': 3, 'E': 5},
           4: {
     'A': 3, 'B': 3, 'C': 1, 'D': 5, 'E': 4},
           5: {
     'A': 1, 'B': 5, 'C': 5, 'D': 2, 'E': 1}
          }
    return items,users

items, users = loadData()
item_df = pd.DataFrame(items).T
user_df = pd.DataFrame(users).T

2.计算用户相似性矩阵 这个是一个共现矩阵, 5*5,行代表每个用户, 列代表每个用户, 值代表用户和用户的相关性,这里的思路是这样, 因为要求用户和用户两两的相关性, 所以需要用双层循环遍历用户-物品评分数据, 当不是同一个用户的时候, 我们要去遍历物品-用户评分数据, 在里面去找这两个用户同时对该物品评过分的数据放入到这两个用户向量中。 因为正常情况下会存在很多的NAN, 即可能用户并没有对某个物品进行评分过, 这样的不能当做用户向量的一部分, 没法计算相似性。 还是看代码吧, 感觉不太好描述:

"""计算用户相似性矩阵"""
similarity_matrix = pd.DataFrame(np.zeros((len(users), len(users))), index=[1, 2, 3, 4, 5], columns=[1, 2, 3, 4, 5])

# 遍历每条用户-物品评分数据
for userID in users:
    for otheruserId in users:
        vec_user = []
        vec_otheruser = []
        if userID != otheruserId:
            for itemId in items:   # 遍历物品-用户评分数据
                itemRatings = items[itemId]        # 这也是个字典  每条数据为所有用户对当前物品的评分
                if userID in itemRatings and otheruserId in itemRatings:  # 说明两个用户都对该物品评过分
                    vec_user.append(itemRatings[userID])
                    vec_otheruser.append(itemRatings[otheruserId])
            # 这里可以获得相似性矩阵(共现矩阵)
            similarity_matrix[userID][otheruserId] = np.corrcoef(np.array(vec_user), np.array(vec_otheruser))[0][1]
            #similarity_matrix[userID][otheruserId] = cosine_similarity(np.array(vec_user), np.array(vec_otheruser))[0][1]

这里的similarity_matrix就是我们的用户相似性矩阵, 长下面这样:
推荐系统(二):协同过滤_第14张图片
有了相似性矩阵, 我们就可以得到与Alice最相关的前n个用户。
3. 计算前n个相似的用户

"""计算前n个相似的用户"""
n = 2
similarity_users = similarity_matrix[1].sort_values(ascending=False)[:n].index.tolist()    # [2, 3]   也就是用户1和用户2

4. 计算最终得分 这里就是上面的那个公式了。

"""计算最终得分"""
base_score = np.mean(np.array([value for value in users[1].values()]))
weighted_scores = 0.
corr_values_sum = 0.
for user in similarity_users:  # [2, 3]
    corr_value = similarity_matrix[1][user]            # 两个用户之间的相似性
    mean_user_score = np.mean(np.array([value for value in users[user].values()]))    # 每个用户的打分平均值
    weighted_scores += corr_value * (users[user]['E']-mean_user_score)      # 加权分数
    corr_values_sum += corr_value
final_scores = base_score + weighted_scores / corr_values_sum
print('用户Alice对物品5的打分: ', final_scores)
user_df.loc[1]['E'] = final_scores
user_df

结果如下:
推荐系统(二):协同过滤_第15张图片
至此, 我们就用代码完成了上面的小例子, 有了这个评分, 我们其实就可以对该用户做推荐了。 这其实就是微型版的UserCF的工作过程了。

UserCF优缺点

User-based算法存在两个重大问题:

数据稀疏性。 一个大型的电子商务推荐系统一般有非常多的物品,用户可能买的其中不到1%的物品,不同用户之间买的物品重叠性较低,导致算法无法找到一个用户的邻居,即偏好相似的用户。这导致UserCF不适用于那些正反馈获取较困难的应用场景(如酒店预订, 大件商品购买等低频应用)

算法扩展性。 基于用户的协同过滤需要维护用户相似度矩阵以便快速的找出Topn相似用户, 该矩阵的存储开销非常大,存储空间随着用户数量的增加而增加,不适合用户数据量大的情况使用。

由于UserCF技术上的两点缺陷, 导致很多电商平台并没有采用这种算法, 而是采用了ItemCF算法实现最初的推荐系统。

基于物品的协同过滤

基于物品的协同过滤(ItemCF)的基本思想是预先根据所有用户的历史偏好数据计算物品之间的相似性,然后把与用户喜欢的物品相类似的物品推荐给用户。比如物品a和c非常相似,因为喜欢a的用户同时也喜欢c,而用户A喜欢a,所以把c推荐给用户A。ItemCF算法并不利用物品的内容属性计算物品之间的相似度, 主要通过分析用户的行为记录计算物品之间的相似度, 该算法认为, 物品a和物品c具有很大的相似度是因为喜欢物品a的用户大都喜欢物品c。推荐系统(二):协同过滤_第16张图片
基于物品的协同过滤算法主要分为两步:

计算物品之间的相似度
根据物品的相似度和用户的历史行为给用户生成推荐列表(购买了该商品的用户也经常购买的其他商品)

基于物品的协同过滤算法和基于用户的协同过滤算法很像, 所以我们这里直接还是拿上面Alice的那个例子来看。
推荐系统(二):协同过滤_第17张图片
如果想知道Alice对物品5打多少分, 基于物品的协同过滤算法会这么做:

**1.**首先计算一下物品5和物品1, 2, 3, 4之间的相似性(它们也是向量的形式, 每一列的值就是它们的向量表示, 因为ItemCF认为物品a和物品c具有很大的相似度是因为喜欢物品a的用户大都喜欢物品c, 所以就可以基于每个用户对该物品的打分或者说喜欢程度来向量化物品)
2找出与物品5最相近的n个物品
3根据Alice对最相近的n个物品的打分去计算对物品5的打分情况
下面我们就可以具体计算一下, 首先是步骤1:
推荐系统(二):协同过滤_第18张图片
由于计算比较麻烦, 这里直接用python计算了:
推荐系统(二):协同过滤_第19张图片
根据皮尔逊相关系数, 可以找到与物品5最相似的2个物品是item1和item4(n=2), 下面基于上面的公式计算最终得分:
这时候依然可以向Alice推荐物品5。下面也是简单编程实现一下, 和上面的差不多:

"""计算物品的相似矩阵"""
similarity_matrix = pd.DataFrame(np.ones((len(items), len(items))), index=['A', 'B', 'C', 'D', 'E'], columns=['A', 'B', 'C', 'D', 'E'])

# 遍历每条物品-用户评分数据
for itemId in items:
    for otheritemId in items:
        vec_item = []         # 定义列表, 保存当前两个物品的向量值
        vec_otheritem = []
        #userRagingPairCount = 0     # 两件物品均评过分的用户数
        if itemId != otheritemId:    # 物品不同
            for userId in users:    # 遍历用户-物品评分数据
                userRatings = users[userId]    # 每条数据为该用户对所有物品的评分, 这也是个字典
                
                if itemId in userRatings and otheritemId in userRatings:   # 用户对这两个物品都评过分
                    #userRagingPairCount += 1
                    vec_item.append(userRatings[itemId])
                    vec_otheritem.append(userRatings[otheritemId])
            
            # 这里可以获得相似性矩阵(共现矩阵)
            similarity_matrix[itemId][otheritemId] = np.corrcoef(np.array(vec_item), np.array(vec_otheritem))[0][1]
            #similarity_matrix[itemId][otheritemId] = cosine_similarity(np.array(vec_item), np.array(vec_otheritem))[0][1]

这里就是物品的相似度矩阵了, 大概长下面这个样子:
推荐系统(二):协同过滤_第20张图片
然后也是得到与物品5相似的前n个物品, 计算出最终得分来。

"""得到与物品5相似的前n个物品"""
n = 2
similarity_items = similarity_matrix['E'].sort_values(ascending=False)[:n].index.tolist()       # ['A', 'D']

"""计算最终得分"""
base_score = np.mean(np.array([value for value in items['E'].values()]))
weighted_scores = 0.
corr_values_sum = 0.
for item in similarity_items:  # ['A', 'D']
    corr_value = similarity_matrix['E'][item]            # 两个物品之间的相似性
    mean_item_score = np.mean(np.array([value for value in items[item].values()]))    # 每个物品的打分平均值
    weighted_scores += corr_value * (users[1][item]-mean_item_score)      # 加权分数
    corr_values_sum += corr_value
final_scores = base_score + weighted_scores / corr_values_sum
print('用户Alice对物品5的打分: ', final_scores)
user_df.loc[1]['E'] = final_scores
user_df

结果如下:
推荐系统(二):协同过滤_第21张图片

协同过滤算法的权重改进

推荐系统(二):协同过滤_第22张图片
1 基础算法 图1为最简单的计算物品相关度的公式, 分子为同时喜好itemi和itemj的用户数
2 对热门物品的惩罚 图1存在一个问题, 如果 item-j 是很热门的商品,导致很多喜欢 item-i 的用户都喜欢 item-j,这时 w{ij}就会非常大。同样,几乎所有的物品都和 item-j 的相关度非常高,这显然是不合理的。所以图2中分母通过引入 N(j)来对 item-j 的热度进行惩罚。如果物品很热门, 那么 N(j)就会越大, 对应的权重就会变小。
对热门物品的进一步惩罚 如果 item-j 极度热门,上面的算法还是不够的。举个例子,《Harry Potter》非常火,买任何一本书的人都会购买它,即使通过图2的方法对它进行了惩罚,但是《Harry Potter》仍然会获得很高的相似度。这就是推荐系统领域著名的 Harry Potter Problem。
3 如果需要进一步对热门物品惩罚,可以继续修改公式为如图3所示,通过调节参数 α,α 越大,惩罚力度越大,热门物品的相似度越低,整体结果的平均热门程度越低。
4 对活跃用户的惩罚 同样的,Item-based CF 也需要考虑活跃用户(即一个活跃用户(专门做刷单)可能买了非常多的物品)的影响,活跃用户对物品相似度的贡献应该小于不活跃用户。图4为集合了该权重的算法。

协同过滤算法的问题分析

协同过滤算法存在的问题之一就是泛化能力弱, 即协同过滤无法将两个物品相似的信息推广到其他物品的相似性上。 导致的问题是热门物品具有很强的头部效应, 容易跟大量物品产生相似, 而尾部物品由于特征向量稀疏, 导致很少被推荐。 比如下面这个例子:
推荐系统(二):协同过滤_第23张图片
A, B, C, D是物品, 看右边的物品共现矩阵, 可以发现物品D与A、B、C的相似度比较大, 所以很有可能将D推荐给用过A、B、C的用户。 但是物品D与其他物品相似的原因是因为D是一件热门商品, 系统无法找出A、B、C之间相似性的原因是其特征太稀疏, 缺乏相似性计算的直接数据。 所以这就是协同过滤的天然缺陷:推荐系统头部效应明显, 处理稀疏向量的能力弱。

为了解决这个问题, 同时增加模型的泛化能力,2006年,矩阵分解技术(Matrix Factorization,MF)被提出, 该方法在协同过滤共现矩阵的基础上, 使用更稠密的隐向量表示用户和物品, 挖掘用户和物品的隐含兴趣和隐含特征, 在一定程度上弥补协同过滤模型处理稀疏矩阵能力不足的问题。 具体细节等后面整理, 这里先铺垫一下。

问题

1.什么时候使用UserCF,什么时候使用ItemCF?为什么?

1 UserCF 由于是基于用户相似度进行推荐, 所以具备更强的社交特性, 这样的特点非常适于用户少, 物品多, 时效性较强的场合, 比如新闻推荐场景, 因为新闻本身兴趣点分散, 相比用户对不同新闻的兴趣偏好, 新闻的及时性,热点性往往更加重要, 所以正好适用于发现热点,跟踪热点的趋势。 另外还具有推荐新信息的能力, 更有可能发现惊喜, 因为看的是人与人的相似性, 推出来的结果可能更有惊喜,可以发现用户潜在但自己尚未察觉的兴趣爱好。
对于用户较少, 要求时效性较强的场合, 就可以考虑UserCF。

2 ItemCF 这个更适用于兴趣变化较为稳定的应用, 更接近于个性化的推荐, 适合物品少,用户多,用户兴趣固定持久, 物品更新速度不是太快的场合, 比如推荐艺术品, 音乐, 电影。 下面是UserCF和ItemCF的优缺点对比: (来自项亮推荐系统实践)

2.协同过滤在计算上有什么缺点?有什么比较好的思路可以解决(缓解)?

较差的稀疏向量处理能力

第一个问题就是泛化能力弱, 即协同过滤无法将两个物品相似的信息推广到其他物品的相似性上。 导致的问题是热门物品具有很强的头部效应, 容易跟大量物品产生相似, 而尾部物品由于特征向量稀疏, 导致很少被推荐。 比如下面这个例子:
推荐系统(二):协同过滤_第24张图片
A, B, C, D是物品, 看右边的物品共现矩阵, 可以发现物品D与A、B、C的相似度比较大, 所以很有可能将D推荐给用过A、B、C的用户。 但是物品D与其他物品相似的原因是因为D是一件热门商品, 系统无法找出A、B、C之间相似性的原因是其特征太稀疏, 缺乏相似性计算的直接数据。 所以这就是协同过滤的天然缺陷:推荐系统头部效应明显, 处理稀疏向量的能力弱。

为了解决这个问题, 同时增加模型的泛化能力,2006年,矩阵分解技术(Matrix Factorization,MF)被提出, 该方法在协同过滤共现矩阵的基础上, 使用更稠密的隐向量表示用户和物品, 挖掘用户和物品的隐含兴趣和隐含特征, 在一定程度上弥补协同过滤模型处理稀疏矩阵能力不足的问题。 具体细节等后面整理, 这里先铺垫一下。

3.上面介绍的相似度计算方法有什么优劣之处?

cosine相似度还是比较常用的, 一般效果也不会太差, 但是对于评分数据不规范的时候, 也就是说, 存在有的用户喜欢打高分, 有的用户喜欢打低分情况的时候,有的用户喜欢乱打分的情况, 这时候consine相似度算出来的结果可能就不是那么准确了, 比如下面这种情况:
推荐系统(二):协同过滤_第25张图片
这时候, 如果用余弦相似度进行计算, 会发现用户d和用户f比较相似, 而实际上, 如果看这个商品喜好的一个趋势的话, 其实d和e比较相近, 只不过e比较喜欢打低分, d比较喜欢打高分。 所以对于这种用户评分偏置的情况, 余弦相似度就不是那么好了, 可以考虑使用下面的皮尔逊相关系数。

4.协同过滤还存在其他什么缺陷?有什么比较好的思路可以解决(缓解)?

协同过滤的特点就是完全没有利用到物品本身或者是用户自身的属性, 仅仅利用了用户与物品的交互信息就可以实现推荐,比较简单高效, 但这也是它的一个短板所在, 由于无法有效的引入用户年龄, 性别,商品描述,商品分类,当前时间,地点等一系列用户特征、物品特征和上下文特征, 这就造成了有效信息的遗漏,不能充分利用其它特征数据。

为了解决这个问题, 在推荐模型中引用更多的特征,推荐系统慢慢的从以协同过滤为核心到了以逻辑回归模型为核心, 提出了能够综合不同类型特征的机器学习模型。

演化图左边的时间线梳理完毕:
在这里插入图片描述

参考资料

基于用户的协同过滤来构建推荐系统:https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw
协同过滤算法概述:https://chenk.tech/posts/8ad63d9d.html
B站黑马推荐系统实战课程

你可能感兴趣的:(RS,机器学习,算法)