推荐算法及其一个算法案例

三、推荐算法

1)推荐模型构建流程

Data(数据)—>Features(特征)—>ML Algorithm(选择算法训练模型)—>Prediction Output(预测输出)

  • 数据清洗/数据处理
    • 数据来源
      • 显性数据
        • 比如用户的评分、评价等
      • 隐性数据
        • 历史订单、点击记录、搜索记录
    • 数据量/数据能否满足要求
  • 特征工程
    • 从数据中筛选特征
    • 用数据表述特征
  • 选择合适的算法
    • 协同过滤
    • 基于内容
  • 产生推荐结果
    • 对推荐结果进行评估

2)最经典的推荐算法:协同过滤

算法的思想:物以类聚,人以群分

基本的协同过滤推荐算法基于以下的假设:

  • 跟你喜好相似的人喜欢的东西你也很有可能喜欢:基于用户的协同过滤推荐
  • 跟你喜欢的东西相似的东西你也很有可能喜欢:基于物品的协同过滤推荐
实现协同过滤推荐的步骤:
  • 1.找出最相似的人或物品:TOP-N相似的人或物品

    通过计算两两的相似度来进行排序,找出TOP-N相似人或者物品

  • 2.根据相似的人或物品产生推荐结果

    利用TOP-N结果生成初始推荐结果,然后过滤掉用户已经有过记录的物品或明确表示过不喜欢的物品

3)相似度计算

相似度的计算方法
  • 欧式距离:衡量两个点的直线距离,不适合做布尔向量计算,它的值是一个非负数,最大值正无穷,通常计算相似度的结果是[-1,1]或[0,1]之间。
    • 余弦相似度
      • 度量两个向量之间的夹角,用夹角的余弦值来度量相似的情况
      • 两个向量的夹角为0,余弦值为1,夹角为90度,余弦值为0,夹角为180,余弦值为-1
      • 余弦相似度在度量文本相似度、用户相似度和物品相似度的时候较为常用
      • 预先相速度的特点:与向量长度无关,需要对向量长度归一化,两个向量只要方向一致,无论程度强弱,都可以视为相似
  • 皮尔逊相关系数Pearson
    • 实际上也是余弦相似度,不过就是对向量做了中心化处理,向量a和b各自减去向量的均值后,再计算余弦相似度
    • 皮尔逊相似度计算结果在[-1,1]之间,-1表示负相关,1表示正相关
    • 度量两个遍历是不是同增同减,变化趋势是否一致,不适合计算布尔向量
  • 杰卡德相似度Jaccard
    • 两个集合的交集元素个数在并集中所占的比例,适合用于布尔向量
    • 就是交集比上并集
  • 如何选择余弦相似度
    • 余弦和皮尔逊适合处理用户的一些评分数据,不适合处理boolearn
    • 杰卡德适合做boolearn类型的数据

以下有一个简单的小案例,数据集相当于一个用户对物品的购买记录

User-Based CF

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y2DiNVfs-1581990726736)(file:///C:/Users/%E6%B8%85%E9%A3%8E/Desktop/%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80%E8%AF%BE%E4%BB%B6/_book/day01_%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E4%BB%8B%E7%BB%8D/img/%E5%9F%BA%E4%BA%8E%E7%94%A8%E6%88%B7%E7%9A%84%E5%8D%8F%E5%90%8C%E8%BF%87%E6%BB%A4%E6%8E%A8%E8%8D%901.png)]

Item-Based CF

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LC7HTyq2-1581990726739)(file:///C:/Users/%E6%B8%85%E9%A3%8E/Desktop/%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80%E8%AF%BE%E4%BB%B6/_book/day01_%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E4%BB%8B%E7%BB%8D/img/%E5%9F%BA%E4%BA%8E%E7%89%A9%E5%93%81%E7%9A%84%E5%8D%8F%E5%90%8C%E8%BF%87%E6%BB%A4%E6%8E%A8%E8%8D%901.png)]

代码实现:User_Based CF
# 根据表格构建数据集
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 用户购买记录数据集
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],
]
import pandas as pd
df = pd.DataFrame(data=datasets,index=users,columns=items)

# 这里我们使用杰卡德相似系数来计算相似度
from sklearn.metrics.pairwise import pairswise_distances

# 计算用户之间的相似度  1 - 杰卡德距离 = 杰卡德相似度
user_similar = 1 - pairwise_distances(df,metric = 'jaccard')
user_similar = pd.DataFrame(data=user_similar,index=users,columns=users)

# 接下来计算TOP-N相似结果 (相似度最接近的前两名用户)
topN_users = {}
for i in user_similar.index:
    _df = user_similar.loc[i].drop(i)
    _df_sorted = _df.sort_values(ascending=False)
    top2 = list(_df_sorted.index[:2])
    topN_users[i] = top2

import numpy as np
results = {}
for user,sim_users in topN_users.items():
    res = set()
    for sim_user in sim_users:
        res = res.union(set(df.loc[sim_user].replace(0,np.NaN).dropna().index))
    # 过滤掉用户已经购买过的物品
    res -= set(df.loc[user].replace(0,np.NaN).dropna().index)
    results[user] = res
    
print("最终推荐结果:",results)
        
Item_Based CF
# 根据表格构建数据集
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 用户购买记录数据集
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],
]
import pandas as pd
df = pd.DataFrame(data=datasets,index=users,columns=items)

# 计算用户之间的相似度  1 - 杰卡德距离 = 杰卡德相似度
item_similar = df.pairwise_distances(df,matric = 'jaccard')
item_similar = pd.DataFrame(data=item_similar,index=items,columns=items)

# # 接下来计算TOP-N相似结果 (相似度最接近的前两名用户)
topN_items = {}
for i in item_similar.index:
    # 取出每一列数据,并删除自身,然后排序数据
    _df = item_similar.loc[i].drop(i)
    _df_sorted = _df.sort_values(ascending=False)
    
    top2 = list(_df_sorted.index[:2])
    topN_items[i] = top2
    
    
results = {}
for user in df.index:
	res = set()
    # 取出每一个用户当前已购买的物品列表
    for item in df.loc[user].replace(0,np.NaN).dropna().index:
        # 根据每个物品找出最相似的TOP-N物品,构建初始推荐结果
        res = res.union(topN_items[item])
        
    # 过滤用户已买过的物品
    res -= set(df.loc[user].replace(0,np.NaN).dropna().index)
    results[user] = res
    
print("最终推荐结果",results)

4)案例:基于协同过滤的电影推荐

1.User-Based CF 预测电影评分

import numpy as np
import pandas as pd

# 获取数据
dtype = {'userId':np.int32,'movieId':np.int32,'rating':np.float32}
# 只取前三列数据 用户id 电影id 和 电影对应评分
ratings = pd.read_csv('ratings.csv',dtype=dtype,usecols=range(3))
# 使用透视表,将电影ID转换为列名称,转换成一个User_Movie的评分矩阵
ratings_matrix = ratings.pivot_table(index=['userId'],columns=['movieId'],values='rating')
# 计算用户之间的相似度   corr就是可以直接计算皮尔逊相关系数
user_similar = ratings.matrix.T.corr()

# 预测某一用户对某一个电影的评分
def predict(uid,iid,ratings_matrix,user_similar):
    
    # 1.找出与用户相似的相似用户
    # 1.1 先删除自己与自己的相似度
    similar_users = user_similar.loc[uid].drop(uid).dropna()
    # 1.2 找出正相关的相似用户
    similar_users = similar_users.where(similar_users > 0 ).dropna()
    # 2.从近邻用户中选出对iid电影有评分的用户
    ids = set(ratings_matrix[iid].dropna().index)&set(similar_users.index)
    # 2.1 将这些用户从相似用户中提取出来
    finally_similar_users = similar_users.loc[list(ids)]
    
    # 3.结合用户与近邻用户的相似度 预测用户对iid电影的评分
    num = 0  # 评分预测公式的分子部分
    deno = 0 # 评分预测公式的分母部分
    for sim_uid,similarity in finally_similar_user.iteritems():
        # 计算这个近邻用户对所有电影的评分
        sim_user_rated_movies = ratings_matrix.loc[sim_uid].dropna()
        # 求出这个用户对iid当前的电影的评分
        sim_user_for_item = sim_user_rated_movies[iid]
        # 计算分子
        num += similarity * sim_user_for_item
        deno += similarity
        
    # 计算预测的评分
    predict_rating = num / deno
    print("预测出用户<%d>对电影<%d>的评分:%0.2f" % (uid,iid,predict_rating))
    return round(predct_rating,2)

# 预测某一个用户对所有电影评分
def predict_all(uid,ratings_matrix,user_similar):
    
    # 准备要预测的电影列表
    item_ids = ratings_matrix.columns
    for iid in item_ids:
        try:
            rating = predict(uid,iid,ratings_matrix,user_similar)
        except Exception as e:
			print(e)
        else:
            yield uid,iid,rating
# 根据评分为指定用户推荐topN个电影
def top_k_result(k):
    results = predict_all(1,ratings_matrix,user_similar)
    return sorted(results,key=lambda x:x[2],reverse = True)[:k]

result = top_k_result(5)
print(result)


发布了104 篇原创文章 · 获赞 33 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/WangTaoTao_/article/details/104369851