基于用户的协同过滤以及ALS的混合召回算法

文章目录

  • 需求
  • 基于用户的协同过滤
    • 基本步骤
    • 相似度计算
    • 代码示例(使用余弦相似度)
    • 基于用户的协同过滤的缺点
    • 实际推荐系统中的替代方案
  • ALS
  • userBase CF+ALS混合推荐设计
  • 代码
  • 说明

需求

要将基于用户的协同过滤(User-Based Collaborative Filtering,
UBCF)与交替最小二乘(Alternating Least Squares, ALS)结合起来,设计一个混合推荐系统。这种系统可以利用
ALS 的优点(如处理稀疏数据的能力)来改进基于用户的协同过滤

基于用户的协同过滤

基于用户之间的相似度来进行推荐。在基于用户的协同过滤中,系统寻找与目标用户兴趣相似的其他用户,然后推荐这些相似用户喜欢的物品给目标用户

基本步骤

基于用户的协同过滤的基本步骤如下:

  • 构建用户-物品评分矩阵:其中行代表用户,列代表物品。矩阵中的每个元素表示用户对物品的评分。
  • 计算用户相似度:
    使用某种相似度度量方法(如皮尔逊相关系数、余弦相似度等)计算用户之间的相似度。
    相似度度量反映了用户之间兴趣的一致性。
  • 找到最近邻用户:
    为每个目标用户找到一组最相似的用户(即最近邻用户)。
    这些最近邻用户的选择通常是基于最高的相似度得分。
  • 生成推荐列表:
    从最近邻用户喜欢的物品中选择未被目标用户评分过的物品作为推荐。
    可以根据最近邻用户的评分和相似度加权平均来预测目标用户对这些物品的潜在评分。

相似度计算

  • 皮尔逊相关系数:
    计算两个用户评分之间的相关性。
    适用于当用户评分分布相同时的情况。
  • 余弦相似度:
    衡量两个用户评分向量之间的角度。
    适用于当用户评分范围差异较大时的情况。
  • Jaccard 相似度:
    仅考虑用户是否对物品有过评分,而不考虑评分的具体数值。
    适用于二元评分(如喜欢/不喜欢)的情况。

代码示例(使用余弦相似度)

因为不同用户直接的评分范围差异比较大 使用余弦相似度来计算

import numpy as np
from scipy.spatial.distance import cosine
from collections import defaultdict

def calculate_similarity(ratings_matrix):
    # 计算用户之间的余弦相似度  返回相似度矩阵 user*user
    num_users = ratings_matrix.shape[0]
    similarity_matrix = np.zeros((num_users, num_users))
    for i in range(num_users):
        for j in range(i + 1, num_users):
            sim = 1 - cosine(ratings_matrix[i], ratings_matrix[j]) # 计算向量之间相似度
            similarity_matrix[i][j] = sim
            similarity_matrix[j][i] = sim
    return similarity_matrix

def get_top_n_recommendations(user_id, ratings_matrix, similarity_matrix, n=10):
    # 获取目标用户的最近邻用户
    target_user_ratings = ratings_matrix[user_id]
    target_user_similarities = similarity_matrix[user_id]
    
    # 计算每个物品的预测评分
    predicted_ratings = defaultdict(float)
    for neighbor_id, similarity in enumerate(target_user_similarities):
       ## 不考虑相似度低的用户
        if similarity < threshold:
            continue
        if neighbor_id == user_id:
            continue  # 跳过自身
        neighbor_ratings = ratings_matrix[neighbor_id] ## 相似用户的评分
        for item_id, rating in enumerate(neighbor_ratings):
        # 检查物品是否已经被目标用户评分过。
        #如果是未评分的物品(即目标用户对该物品的评分是 0),并且邻居用户对该物品有评分(评分大于 0),则进行以下操作
            if rating > 0 and target_user_ratings[item_id] == 0:
                predicted_ratings[item_id] += similarity * rating
    
    # 根据预测评分排序
    recommendations = sorted(predicted_ratings.items(), key=lambda x: x[1], reverse=True)[:n]
    return recommendations

# 示例数据
ratings_matrix = np.array([
    [5, 3, 0, 1],
    [4, 0, 0, 1],
    [1, 1, 0, 5],
    [1, 0, 0, 4],
    [0, 1, 5, 4]
])

similarity_matrix = calculate_similarity(ratings_matrix)

# 获取用户 0 的推荐
top_n_recommendations = get_top_n_recommendations(0, ratings_matrix, similarity_matrix, n=2)
print("Top 2 Recommendations for User 0:")
for item_id, prediction in top_n_recommendations:
    print(f"Item {item_id}: {prediction:.2f}")

基于用户的协同过滤是一种经典的推荐算法,它通过寻找具有相似兴趣的用户来推荐物品,它关注的是用户之间的相似性而非物品之间的相似性。然而,在大规模数据集上,这种方法可能会因为计算用户相似度矩阵所需的大量计算资源而变得不太实用

基于用户的协同过滤的缺点

  • 计算成本高:
    需要计算所有用户之间的相似度,这在用户基数很大的情况下是非常耗时且计算密集的。
    对于大型数据集,计算用户之间的相似度矩阵可能会成为瓶颈。
  • 冷启动问题:
    新加入系统的用户(新用户)没有历史评分记录,难以找到相似用户。
    同样地,新物品也面临相似问题,因为没有足够的用户对其进行评分。
  • 稀疏性问题:
    大多数用户只会对一小部分物品进行评分,导致用户-物品评分矩阵非常稀疏。
    稀疏性问题使得计算用户之间的相似度变得更加困难,因为可用的共同评分物品较少。
  • 可扩展性差:
    当用户基数增加时,计算所有用户之间的相似度变得越来越不可行。
    在实时推荐场景下,需要频繁更新用户之间的相似度,这会增加计算负担。
  • 数据稀疏性和噪声:
    由于用户通常只会对少数物品进行评分,导致评分数据非常稀疏,这会影响相似度计算的准确性。
    用户的评分可能存在噪声,比如误评、情绪化评分等,这也会影响到相似度计算的准确性。

实际推荐系统中的替代方案

鉴于上述缺点,现代推荐系统通常采用其他技术或组合多种技术来克服这些问题:

  • 基于物品的协同过滤(Item-Based Collaborative Filtering, IBCF):
    相比于用户之间的相似度,计算物品之间的相似度更加高效。
    物品的数量通常少于用户数量,因此计算物品相似度的成本相对较低。
  • 矩阵分解(Matrix Factorization):
    如交替最小二乘(Alternating Least Squares, ALS)、奇异值分解(SVD)等技术,可以有效处理稀疏性问题,并且能够处理大规模数据集。
  • 深度学习方法:
    利用神经网络模型来捕捉复杂的用户偏好和物品特征之间的关系。
    例如深度神经网络(DNN)、卷积神经网络(CNN)、循环神经网络(RNN)等。
  • 混合推荐系统:
    结合多种推荐技术的优点,比如结合基于用户的协同过滤、基于物品的协同过滤以及矩阵分解等。这样的系统可以更好地处理稀疏性、冷启动等问题,并提供更高质量的推荐。

ALS

参照
推荐系统中ALS验证

userBase CF+ALS混合推荐设计

  • 构建用户-物品评分矩阵。
  • 使用 ALS 训练模型。
  • 计算用户之间的相似度。
  • 生成基于用户相似度的推荐。
  • 融合 ALS 推荐和基于用户相似度的推荐

代码

import numpy as np
from scipy.sparse import csr_matrix
from scipy.sparse.linalg import svds
from sklearn.metrics.pairwise import cosine_similarity
from collections import defaultdict

def calculate_similarity(ratings_matrix):
    # 计算用户之间的余弦相似度
    similarity_matrix = cosine_similarity(ratings_matrix)
    return similarity_matrix

def als_train(ratings_matrix, latent_features=10, learning_rate=0.001, reg_param=0.02, iterations=100):
    # 初始化用户和物品的特征向量
    user_features = np.random.normal(scale=1./latent_features, size=(ratings_matrix.shape[0], latent_features))
    item_features = np.random.normal(scale=1./latent_features, size=(ratings_matrix.shape[1], latent_features))

    # 训练 ALS 模型
    for iteration in range(iterations):
        for u, rated_items in enumerate(ratings_matrix):
            items, ratings = zip(*[(i, r) for i, r in enumerate(rated_items) if r > 0])
            item_matrix = item_features[items]
            user_features[u] = np.linalg.solve(item_matrix.T @ item_matrix + reg_param * len(items) * np.eye(latent_features),
                                                item_matrix.T @ ratings).ravel()

        for i, rated_users in enumerate(ratings_matrix.T):
            users, ratings = zip(*[(u, r) for u, r in enumerate(rated_users) if r > 0])
            user_matrix = user_features[users]
            item_features[i] = np.linalg.solve(user_matrix.T @ user_matrix + reg_param * len(users) * np.eye(latent_features),
                                                user_matrix.T @ ratings).ravel()

    return user_features, item_features

def get_top_n_recommendations(user_id, ratings_matrix, user_features, item_features, n=10):
    # 生成基于 ALS 的推荐
    predictions_als = user_features[user_id].dot(item_features.T)
    
    # 生成基于用户相似度的推荐
    target_user_ratings = ratings_matrix[user_id]
    target_user_similarities = similarity_matrix[user_id]
    predicted_ratings = defaultdict(float)
    for neighbor_id, similarity in enumerate(target_user_similarities):
        if neighbor_id == user_id:
            continue  # 跳过自身
        neighbor_ratings = ratings_matrix[neighbor_id]
        for item_id, rating in enumerate(neighbor_ratings):
            if rating > 0 and target_user_ratings[item_id] == 0:
                predicted_ratings[item_id] += similarity * rating
    
    # 结合 ALS 和基于用户相似度的预测
    combined_predictions = defaultdict(float)
    for item_id in predicted_ratings.keys():
        combined_predictions[item_id] = 0.7 * predictions_als[item_id] + 0.3 * predicted_ratings[item_id]

    # 根据预测评分排序
    recommendations = sorted(combined_predictions.items(), key=lambda x: x[1], reverse=True)[:n]
    return recommendations

# 示例数据
ratings_data = np.array([
    [5, 3, 0, 1],
    [4, 0, 0, 1],
    [1, 1, 0, 5],
    [1, 0, 0, 4],
    [0, 1, 5, 4]
])

# 构建稀疏矩阵
ratings_matrix = csr_matrix(ratings_data)

# 训练 ALS 模型
user_features, item_features = als_train(ratings_matrix)

# 计算用户之间的相似度
similarity_matrix = calculate_similarity(ratings_matrix.toarray())

# 获取用户 0 的推荐
top_n_recommendations = get_top_n_recommendations(0, ratings_matrix, user_features, item_features, n=2)
print("Top 2 Recommendations for User 0:")
for item_id, prediction in top_n_recommendations:
    print(f"Item {item_id}: {prediction:.2f}")

说明

  • ALS 模型训练:
    使用 als_train 函数训练 ALS 模型,得到用户特征向量和物品特征向量。
    这些特征向量用于预测用户对未评分物品的潜在评分。
  • 计算用户相似度:
    使用 calculate_similarity 函数计算用户之间的余弦相似度。
  • 生成推荐:
    使用 get_top_n_recommendations 函数生成推荐列表。
    结合 ALS 的预测评分和基于用户相似度的预测评分。
    通过调整权重(在这个例子中是 0.7 和 0.3)来平衡这两种推荐方法的影响

你可能感兴趣的:(算法,机器学习,人工智能,矩阵,python,推荐算法,线性代数)