推荐系统实战(二)

推荐算法

  • 推荐模型构建流程
  • 推荐算法概述
  • 基于协同过滤的推荐算法
  • 协同过滤实现

一 推荐模型构建流程

Data(数据)->Features(特征)->ML Algorithm(机器学习算法)->Prediction Output(预测输出)

  • 数据清洗/数据处理

  • 数据来源
    • 显性数据
      • Rating 打分
      • Comments 评论/评价
    • 隐形数据
      •  Order history 历史订单
      •  Cart events 加购物车
      •  Page views 页面浏览
      •  Click-thru 点击
      •  Search log 搜索记录
  • 数据量/数据能否满足要求
  • 特征工程

  • 从数据中筛选特征
    • 一个给定的商品,可能被拥有类似品味或需求的用户购买
    • 使用用户行为数据描述商品

  • 用数据表示特征

    • 将所有用户行为合并在一起 ,形成一个user-item 矩阵

      1545452707102

  • 选择合适的算法

  • 产生推荐结果

二 推荐算法概述

2.1 常用推荐算法

  • 基于内容过滤
    • 从信息检索,和文本检索发展而来
    • 基于商品描述及用户喜好描述,为用户推荐商品
  • 协同过滤
    • 基于用户行为为用户推荐感兴趣的商品
    • 行为可以是过往的交易行为和商品评分,这种方式不需要显性的属性信息
  • 混合推荐

2.2 基于内容过滤存在的问题

  • 需了解商品内容

    • 需要人工或自动标注信息
    • 商品内容不能反映所有特点
  • 冷启动问题

    • 需要花时间学习哪些内容或feature 对用户而言是重要的
  • 如果用户兴趣点改变了呢

  • Lack of serendipity(缺少意外新发现 EE问题)

    1545453690391

  • 基于内容的推荐(Content-based) V.S. 协同过滤(Collaborative Filtering)

推荐方法 优点 缺点
基于内容推荐 推荐结果直观,容易解释 不需要领域知识 新用户问题; 复杂属性不好处理; 要有足够数据构造分类器;
协同过滤推荐 新异兴趣发现、不需要领域知识;
随着时间推移性能提高;
推荐个性化、自动化程度高;
能处理复杂的非结构化对象;
稀疏问题; 可扩展性问题; 新用户问题; 依赖历史数据集; 系统开始时推荐质量差;

三 基于协同过滤的推荐算法

3.1 协同过滤算法概述

  • 协同过滤算法

    • 基于用户行为的推荐
    • 行为可以是过往的交易行为和商品评分,这种方式不需要显性的属性信息
  • 协同过滤分类

    • K近邻(neighborhood )方法
      • 借助商品的关系或者用户的关系
  • 基于模型的方法
    • 用隐含变量刻画商品

3.2 协同过滤算法之K邻近方法

  • K邻近方法
    基于假设 : “跟你喜好相似的人喜欢的东西你也很有可能喜欢” 或“跟你喜欢的物品类似的物品你也很有可能喜欢 ”
  • 分类
    • User-based 方法
      • 基于user的协同过滤,通过不同用户对item的评分来评测用户之间的相似性,基于用户之间的相似性做出推荐
    • Item-based方法
      • 基于item的协同过滤,通过用户对不同item的评分来评测item之间的相似性,基于item之间的相似性做出推荐
  • 基于用户(User-based)
    • 查找用户相似度 如何预测用户1对于商品4的喜好程度?
      • 找到和用户1相似的用户且购买过商品4(基于购买记录)即为用户n
      • 根据用户n对商品4的评价,以相似度为权重回填结果
      • 针对所有用户组合,重复上述步骤,直到所有空格都被填满

1545455898171

  • 找到相似的Item (Item-based)

    • 用户1对于商品4的喜好程度?
    1. 从用户1历史记录中,计算商品n和商品4的相似度(以其他用户的历史记录)
    2. 将用户1对于商品n的评价,以商品相似度为权重回填
    3. 针对所有商品组合,重复上述步骤直到所有空格都被填满

1545456021921

  • 用户&物品矩阵

  • 将订单数据填入到用户-物品矩阵

  • 处理用户-物品数据(归一化)

  • 处理用户-物品矩阵 填充矩阵中的空值

3.3 相似度计算(Similarity Calculation)

  • 数据分类
    • 实数值(物品评分情况)
    • 布尔值(用户的行为 是否点击 是否收藏)

欧氏距离

欧氏距离是一个欧式空间下度量距离的方法. 两个物体, 都在同一个空间下表示为两个点, 假如叫做p,q, 分别都是n个坐标, 那么欧式距离就是衡量这两个点之间的距离. 欧氏距离不适用于布尔向量之间

欧氏距离的值是一个非负数, 最大值正无穷, 通常计算相似度的结果希望是[-1,1]或[0,1]之间,一般可以使用如下转化公式:

杰卡德相似度&余弦相似度&皮尔逊相关系数

余弦相似度

  • 度量的是两个向量之间的夹角, 用夹角的余弦值来度量相似的情况
  • 两个向量的夹角为0是,余弦值为1, 当夹角为90度是余弦值为0,为180度是余弦值为-1
  • 余弦相似度在度量文本相似度, 用户相似度 物品相似度的时候较为常用
  • 余弦相似度的特点, 与向量长度无关,余弦相似度计算要对向量长度归一化, 两个向量只要方向一致,无论程度强弱, 都可以视为’相似’
  • 余弦相似度对绝对值大小不敏感带来的问题
    • 用户A对两部电影评分分别是1分和2分, 用户B对同样这两部电影进行评分是4分,5分 用余弦相似度计算,两个用户的相似度达到0.98
    • 可以采用改进的余弦相似度, 先计算向量每个维度上的均值, 然后每个向量在各个维度上都减去均值后,在计算余弦相似度, 用调整的余弦相似度计算得到的相似度是-0.1,计算公式为$s(i,j) = \frac{\sum_{c\in U}(R_{u,i}-\bar R_u)(R_{u,j}-\bar R_u)}{\sqrt{\sum_{u\in U}(R_{u,i}-\bar R_u)^2}\sqrt{\sum_{u\in U}(R_{u,j}-\bar R_u)^2}}$
皮尔逊相关系数Pearson
  • 实际上也是一种余弦相似度, 不过先对向量做了中心化, 向量a b 各自减去向量的均值后, 再计算余弦相似度
  • 皮尔逊相似度计算结果在-1,1之间 -1表示负相关, 1表示正相关
  • 度量两个变量是不是同增同减
  • 皮尔逊相关系数度量的是两个变量的变化趋势是否一致, 不适合计算布尔值向量之间的相关度
杰卡德相似度 Jaccard
  • 两个集合的交集元素个数在并集中所占的比例, 非常适用于布尔向量表示
  • 分子是两个布尔向量做点积计算, 得到的就是交集元素的个数
  • 分母是两个布尔向量做或运算, 再求元素和

  • 余弦相似度适合用户评分数据(实数值), 杰卡德相似度适用于隐式反馈数据(0,1布尔值)(是否收藏,是否点击,是否加购物车)

推荐步骤

  • 计算出用户1和其它用户之间的相似度

  • 按照相似度大小排序, K近邻 如K取4:

  • 取出近邻用户的购物清单

  • 去除用户1已经购买过的商品

  • 在剩余的物品中根据评分排序

物品相似度计算案例

  • 找出物品1的相似商品

  • 选择最近似的物品

3.4 基于模型的方法

  • 思想

    • 通过机器学习算法,在数据中找出模式,并将用户与物品间的互动方式模式化
    • 基于模型的协同过滤方式是构建协同过滤更高级的算法
  • 近邻模型的问题

    • 物品之间存在相关性, 信息量并不随着向量维度增加而线性增加
    • 矩阵元素稀疏, 计算结果不稳定,增减一个向量维度, 导致近邻结果差异很大的情况存在
  • 算法分类

    • 基于图的模型
    • 基于矩阵分解的方法
  • 基于图的模型

    • 基于邻域的模型看做基于图的模型的简单形式

    • 原理
      • 将用户的行为数据表示为二分图
      • 基于二分图为用户进行推荐
      • 根据两个顶点之间的路径数、路径长度和经过的顶点数来评价两个顶点的相关性
  • 基于矩阵分解的模型

    • 原理

      • 根据用户与物品的潜在表现,我们就可以预测用户对未评分的物品的喜爱程度

      • 把原来的大矩阵, 近似分解成两个小矩阵的乘积, 在实际推荐计算时不再使用大矩阵, 而是使用分解得到的两个小矩阵

      • 用户-物品评分矩阵A是$M \text{x} N$维, 即一共有$M$个用户, $N$个物品 我们选一个很小的数 $K (K<< M, K<<N)$

      • 通过计算得到两个矩阵$U$ 和 $V$,其中$U$是$M \text{x} K$矩阵 , $V$是$N \text{x} K$矩阵,$U_{m\text{x}k} V^{T}_{n\text{x}k}$ 约等于 $A_{m\text{x}n}$

        类似这样的计算过程就是矩阵分解

    • 基于矩阵分解的方法

      • ALS交替最小二乘
        • ALS-WR(加权正则化交替最小二乘法): alternating-least-squares with weighted-λ –regularization
        • 将用户(user)对商品(item)的评分矩阵分解为两个矩阵:一个是用户对商品隐含特征的偏好矩阵,另一个是商品所包含的隐含特征的矩阵。在这个矩阵分解的过程中,评分缺失项得到了填充,也就是说我们可以基于这个填充的评分来给用户做商品推荐了。
      • SVD奇异值分解矩阵
  • ALS方法

    • ALS的矩阵分解算法常应用于推荐系统中,将用户(user)对商品(item)的评分矩阵,分解为用户对商品隐含特征的偏好矩阵,和商品在隐含特征上的映射矩阵。
    • 与传统的矩阵分解SVD方法来分解矩阵$R(R∈ℝm×n)$不同的是,ALS(alternating least squares)希望找到两个低维矩阵,以 $R̃ =XY$来逼近矩阵R,其中 $X∈ℝ_{m×d},Y∈ℝ_{d×n}$,这样,将问题的复杂度由$O(mn)$转换为$O((m+n)d)$。
    • 计算$X$和$Y$过程:首先用一个小于1的随机数初始化$Y$,并根据公式求$X$,此时就可以得到初始的$XY$矩阵了,根据平方差和得到的X,重新计算并覆盖$Y$,计算差平方和,反复进行以上两步的计算,直到差平方和小于一个预设的数,或者迭代次数满足要求则停止

3.5 基于用户的协同过滤实现 (User CF)

思路

  • 第一步: 找出和目标用户兴趣类似的用户集合
  • 第二步: 找到集合中用户喜欢的,且目标用户没有听说过的物品推荐给目标用户

实现步骤

计算用户相似度

  • 设$N(u)$是用户$u$有过正反馈的物品集合,则Jaccard公式:

  • 如果用户数目很多,如何优化?
    答:首先计算出$N(u)\cap N(v) != 0$的用户对$(u,v)$,然后再对这种情况除以分母$\sqrt{(N(u)*N(v))}$

推荐相似用户喜欢的物品

  • 得到用户之间的兴趣相似度后,UserCF算法会给用户推荐和他兴趣最相似的$K$个用户喜欢的物品。

  • $S(u, K)$包含和用户u兴趣最接近的$K$个用户,$N(i)$是对物品i有过行为的用户集合,$W_{uv}$是用户u和用户v的兴趣相似度,$r_{vi}$代表用户$v$对物品$i$的兴趣,因为使用的是单一行为的隐反馈数据,所以所有的$r_{vi}$=1

  • 选取$K=3$,用户A对物品c、e没有过行为,因此可以把这两个物品推荐给用户A。

3.6 基于物品的协同过滤实现 (Item CF)

思路

  • Step 1:计算物品之间的相似度
  • Step 2:根据物品的相似度和用户的历史行为,为用户生成推荐列表

实现步骤

代码实现

下面分为0-1型数据及评分型数据分别进行协同过滤,这两者的区别主要在于相关系数的衡量方式不同,其中评分型数据还分为稀疏型和稠密型两种

数据为0-1型(调用和没调用)

第一步:计算相似度

生成数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd
from sklearn.metrics import jaccard_score

users = ["user1", "user2", "user3", "user4", "user5"]
items = ["itemA", "itemB", "itemC", "itemD", "itemE",]

datasets = [
[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],
]

df = pd.DataFrame(datasets, columns=items, index=users)
print(df)

生成数据的打印结果为:

1
2
3
4
5
6
       itemA  itemB  itemC  itemD  itemE
user1 1 0 1 1 0
user2 1 0 0 1 1
user3 1 0 1 0 0
user4 0 1 0 1 1
user5 1 1 1 0 1

计算杰卡德相似度

1
jaccard_score(df["itemA"], df["itemB"]) # 0.2

用户相似度的计算方式为:

1
2
3
4
from sklearn.metrics.pairwise import pairwise_distances
user_simility = 1 - pairwise_distances(df.values, metric="jaccard")
user_similar = pd.DataFrame(user_simility, columns=users, index=users)
user_similar

用户相似度的打印结果为:

1
2
3
4
5
6
          user1  user2     user3  user4  user5
user1 1.000000 0.50 0.666667 0.2 0.4
user2 0.500000 1.00 0.250000 0.5 0.4
user3 0.666667 0.25 1.000000 0.0 0.5
user4 0.200000 0.50 0.000000 1.0 0.4
user5 0.400000 0.40 0.500000 0.4 1.0

物品相似度的计算方式为:

1
2
3
item_simility = 1 - pairwise_distances(df.T.values, metric="jaccard")
item_similar = pd.DataFrame(item_simility, columns=items, index=items)
item_similar

用户相似度的打印结果为:

1
2
3
4
5
6
       itemA     itemB  itemC  itemD     itemE
itemA 1.00 0.200000 0.75 0.40 0.400000
itemB 0.20 1.000000 0.25 0.25 0.666667
itemC 0.75 0.250000 1.00 0.20 0.200000
itemD 0.40 0.250000 0.20 1.00 0.500000
itemE 0.40 0.666667 0.20 0.50 1.000000

第二步:进行推荐

1. 为每一个用户找到最相似的K个用户

1
2
3
4
5
6
7
8
9
10
topN_user = {}
K = 2
for i in user_similar.index:
# 取出一列数据,删除自己后按照相似度排序
_df = user_similar.loc[i].drop([i])
_df_sorted = _df.sort_values(ascending = False)
topK = list(_df_sorted.index[:K])
topN_user[i] = topK

topN_user
1
2
3
4
5
{'user1': ['user3', 'user2'],
'user2': ['user4', 'user1'],
'user3': ['user1', 'user5'],
'user4': ['user2', 'user5'],
'user5': ['user3', 'user4']}

2. 根据TopN的相似用户构建推荐结果

1
2
3
4
5
6
7
8
9
10
rs_results = {}
for user, sim_users in topN_user.items():
rs_result = set()
for sim_user in sim_users:
rs_result = rs_result.union(set(df.loc[sim_user].replace(0, np.nan).dropna().index))
# 过滤掉已经购买的商品
rs_result -= set(df.loc[user].replace(0, np.nan).dropna().index)
rs_results[user] = rs_result

rs_results

打印结果为:

1
2
3
4
5
{'user1': {'itemE'},
'user2': {'itemB', 'itemC'},
'user3': {'itemB', 'itemD', 'itemE'},
'user4': {'itemA', 'itemC'},
'user5': {'itemD'}}

数据为评分型

我们采用皮尔逊相关系数$[-1,1]$来计算,其中-1代表强负相关,+1代表强正相关

1
2
3
4
5
6
7
8
9
10
11
12
13
users = ["user1", "user2", "user3", "user4", "user5"]
items = ["itemA", "itemB", "itemC", "itemD", "itemE",]

datasets = [
[5,3,4,4,None],
[3,1,2,3,3],
[4,3,4,3,5],
[3,3,1,5,4],
[1,5,5,2,1],
]

df = pd.DataFrame(datasets, columns=items, index=users)
print(df)

数据长得这个样:

1
2
3
4
5
6
       itemA  itemB  itemC  itemD  itemE
user1 5 3 4 4 NaN
user2 3 1 2 3 3.0
user3 4 3 4 3 5.0
user4 3 3 1 5 4.0
user5 1 5 5 2 1.0

计算相似度方式为:

1
2
3
4
5
6
7
print("用户相似度矩阵为:")
user_similar = df.T.corr()
print(user_similar.round(4))

print("物品相似度矩阵为:")
item_similar = df.corr()
print(item_similar.round(4))

打印结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
用户相似度矩阵为:
user1 user2 user3 user4 user5
user1 1.0000 0.8528 0.7071 0.0000 -0.7921
user2 0.8528 1.0000 0.4677 0.4900 -0.9001
user3 0.7071 0.4677 1.0000 -0.1612 -0.4666
user4 0.0000 0.4900 -0.1612 1.0000 -0.6415
user5 -0.7921 -0.9001 -0.4666 -0.6415 1.0000
物品相似度矩阵为:
itemA itemB itemC itemD itemE
itemA 1.0000 -0.4767 -0.1231 0.5322 0.9695
itemB -0.4767 1.0000 0.6455 -0.3101 -0.4781
itemC -0.1231 0.6455 1.0000 -0.7206 -0.4276
itemD 0.5322 -0.3101 -0.7206 1.0000 0.5817
itemE 0.9695 -0.4781 -0.4276 0.5817 1.0000

剩下的就和数据为0-1型的讨论一样了。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2020-2021 chenk
  • 由 帅气的CK本尊 强力驱动
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信