构建AI智能体:三十八、告别“冷启动”:看大模型如何解决推荐系统的世纪难题 - 实践

news/2025/9/20 14:49:01/文章来源:https://www.cnblogs.com/yxysuanfa/p/19102443

一、什么是协同过滤

        协同过滤是推荐系统领域最为经典和广泛应用的技术之一,其基本思想源于我们日常生活中的决策方式。当人们面临选择时,往往会参考与自己品味或需求相似的其他人的意见。比如选择餐厅时,我们会相信美食家的推荐;选购书籍时,我们会关注与自己阅读兴趣相近的朋友的书单。协同过滤正是将这种社会化的决策过程数字化和自动化。

        协同过滤基于一个核心假设:用户偏好具有持久性,过去有相似偏好的用户在未来也会表现出相似的偏好。这个假设虽然简单,但在大多数场景下都被证明是有效的。协同过滤的核心思想可以用一句话概括:物以类聚,人以群分。它不需要了解物品的任何属性信息,仅依靠用户与物品的交互历史(如评分、购买、点击等)发现用户或物品之间的相似性,从而预测用户可能喜欢的内容,就能产生推荐,与基于物品本身属性(如电影类型、商品类别)的推荐不同,协同过滤完全依赖于用户的实际行为,不需要对物品内容进行复杂理解。

协同过滤简单理解:

  • 协同:多个用户共同参与数据贡献,系统利用群体智慧进行推荐
  • 过滤:从海量信息中筛选出用户潜在感兴趣的内容

二、协同过滤的工作原理

工作原理可以分解为三个基本步骤:

  • 首先是模式发现,系统分析所有用户的历史行为数据,寻找用户之间或物品之间的相似性模式;
  • 其次是邻居形成,针对目标用户或目标物品,找到最相似的若干用户或物品;
  • 最后是预测生成,基于邻居的行为预测目标用户对未知物品的偏好程度。

        这种方法的优势在于其直观性和有效性。它不需要领域专业知识,能够发现复杂的、非直观的关联关系。例如,协同过滤可能会发现喜欢购买咖啡机的人往往也喜欢购买特定品牌的咖啡豆,这种关联可能连商家自己都没有意识到。

三、相似度计算方法与细节

        相似度计算是协同过滤的核心技术环节,其准确性直接影响到推荐系统的效果。不同的相似度度量方法从不同角度衡量用户或物品之间的相似性,各有其适用场景和特点。

1. 余弦相似度

        余弦相似度是一种衡量两个向量方向相似程度的度量方法,它将用户评分看作向量空间中的向量,并通过计算两个向量夹角的余弦值来评估它们的相似性。

        它的取值范围在-1到1之间,值越接近1表示两个向量越相似,值越接近-1表示两个向量越相反,值为0表示两个向量正交,没有关联。

        在协同过滤中,我们可以把每个用户看作一个高维空间中的向量,每个维度代表一个物品的评分。余弦相似度帮助我们找到方向相似的用户,即品味相似的用户。余弦相似度的优点是不受向量长度影响,只关注方向,适合处理用户评分尺度不一致的情况。

直观理解:

  • 两个指向相同方向的向量:夹角为0°,余弦值为1(完全相似)
  • 两个垂直的向量:夹角为90°,余弦值为0(不相关)
  • 两个指向相反方向的向量:夹角为180°,余弦值为-1(完全相反)

计算公式:

其中:

  • A⋅B 是向量A和B的点积
  • ∥A∥∥B∥分别是向量A和B的模(长度)

基础示例:简单二维向量

        假设有两个向量: 向量A = [3, 4]  向量B = [1, 2]

计算过程推理:

  • 点积:A·B = 3×1 + 4×2 = 3 + 8 = 11
  • 模长:‖A‖ = √(3² + 4²) = √(9 + 16) = √25 = 5
  • 模长:‖B‖ = √(1² + 2²) = √(1 + 4) = √5 ≈ 2.236
  • 余弦相似度:11 / (5 × 2.236) ≈ 11 / 11.18 ≈ 0.984

用户示例:用户评分向量

        假设两个用户对三部电影的评分:

  • 用户A: [5, 3, 0](给电影1评5分,电影2评3分,没看过电影3)
  • 用户B: [4, 2, 5](给电影1评4分,电影2评2分,电影3评5分)

计算过程推理:

  • 点积:A·B = 5×4 + 3×2 + 0×5 = 20 + 6 + 0 = 26
  • 模长:‖A‖ = √(5² + 3² + 0²) = √(25 + 9 + 0) = √34 ≈ 5.831
  • 模长:‖B‖ = √(4² + 2² + 5²) = √(16 + 4 + 25) = √45 ≈ 6.708
  • 余弦相似度:26 / (5.831 × 6.708) ≈ 26 / 39.11 ≈ 0.665

代码演示:

import numpy as np
def cosine_similarity_basic(vec_a, vec_b):
"""
计算两个向量的余弦相似度
参数:
vec_a: 第一个向量
vec_b: 第二个向量
返回:
余弦相似度值
"""
# 转换为numpy数组
a = np.array(vec_a)
b = np.array(vec_b)
# 计算点积
dot_product = np.dot(a, b)
# 计算模长
norm_a = np.linalg.norm(a)
norm_b = np.linalg.norm(b)
# 计算余弦相似度
if norm_a == 0 or norm_b == 0:
return 0  # 避免除以零
return dot_product / (norm_a * norm_b)
# 测试
vector1 = [3, 4]
vector2 = [1, 2]
similarity = cosine_similarity_basic(vector1, vector2)
print(f"向量{vector1}和{vector2}的余弦相似度: {similarity:.3f}")
# 用户评分示例
user_a = [5, 3, 0]
user_b = [4, 2, 5]
user_similarity = cosine_similarity_basic(user_a, user_b)
print(f"用户A{user_a}和用户B{user_b}的余弦相似度: {user_similarity:.3f}")

输出结果:

向量[3, 4]和[1, 2]的余弦相似度: 0.984
用户A[5, 3, 0]和用户B[4, 2, 5]的余弦相似度: 0.665

2. 皮尔逊相关系数

        皮尔逊相关系数衡量的是两个变量之间的线性相关程度。在协同过滤中,它测量的是两个用户评分模式的一致性,而不是评分的绝对值。皮尔逊相关系数的取值范围也是[-1, 1],正值表示正相关,负值表示负相关。

        与余弦相似度不同,皮尔逊相关系数考虑了用户平均评分的影响,因此能够缓解用户评分严格度不同带来的偏差,能更准确地反映用户品味的相似性。例如,有些用户习惯打高分,有些用户习惯打低分,皮尔逊相关系数能够消除这种个体差异的影响。

计算公式:

其中:

  • $x_i$ 和 $y_i$ 分别是两个用户对同一物品的评分
  • $\bar{x}$ 和 $\bar{y}$ 分别是两个用户的平均评分
  • $n$ 是两个用户共同评分的物品数量

取值范围和解释:

  • r = 1:完全正相关
  • r = -1:完全负相关
  • r = 0:无线性相关
  • 0 < r < 1:正相关(越接近1相关性越强)
  • -1 < r < 0:负相关(越接近-1负相关性越强)

评分过程推理:

假设我们有两个用户(用户A和用户B)对5部电影的评分情况:

电影用户A评分用户B评分
电影154
电影245
电影332
电影421
电影513

第一步:计算平均评分

首先计算每个用户的平均评分:

  • 用户A的平均评分:(5 + 4 + 3 + 2 + 1)/5 = 3
  • 用户B的平均评分:(4 + 5 + 2 + 1 + 3)/5 = 3

第二步:计算评分与平均分的差值

计算每个评分与其相应用户平均分的差值:

电影用户A评分用户B评分A评分差值B评分差值
电影154 5-3 = 24-3 = 1
电影2454-3 = 15-3 = 2
电影3323-3 = 02-3 = -1
电影4212-3 = -11-3 = -2
电影5131-3 = -23-3 = 0

第三步:计算分子部分

计算分子:每部电影的差值的乘积之和

电影A评分差值B评分差值乘积
电影1 212×1 = 2
电影2121×2 = 2
电影30 -10×(-1) = 0
电影4 -1-2(-1)×(-2) = 2
电影5-20(-2)×0 = 0

分子总和 = 2 + 2 + 0 + 2 + 0 = 6

第四步:计算分母部分

分母由两部分组成:

第一部分:取A用户评分差值的平方之和的平方跟

电影A评分差值A差值的平方
电影1 24
电影211
电影30 0
电影4 -11
电影5-24

总和 = 4 + 1 + 0 + 1 + 4 = 10
平方根 = √10 ≈ 3.162 (√为平方根符号)

第二部分:取B用户评分差值的平方之和的平方跟

电影B评分差值B差值的平方
电影111
电影224
电影3 -11
电影4-24
电影500

总和 = 1 + 4 + 1 + 4 + 0 = 10
平方根 = √10 ≈ 3.162 (√为平方根符号)
分母 = 3.162 × 3.162 = 10.000

第五步:计算皮尔逊相关系数

现在我们可以计算最终的皮尔逊相关系数:

r= 分子/分母 = 6/10 = 0.6

结果评估:

  • 正相关:用户A和用户B的评分模式呈现正相关关系
  • 中等强度:0.6的相关性表明两个用户的品味有中等程度的相似性
  • 一致性:当用户A给某部电影评分高于其平均水平时,用户B也倾向于给这部电影评分高于其平均水平

与余弦相似度的对比

为了对比,我们计算一下相同数据的余弦相似度:

余弦相似度计算:

  • 分子:5×4 + 4×5 + 3×2 + 2×1 + 1×3 = 20 + 20 + 6 + 2 + 3 = 51
  • 分母:√(5²+4²+3²+2²+1²) × √(4²+5²+2²+1²+3²) = √(25+16+9+4+1) × √(16+25+4+1+9) = √55 × √55 = 7.416 × 7.416 = 55
  • 余弦相似度:51/55 ≈ 0.927

对比分析:

  • 余弦相似度:0.927(非常高)
  • 皮尔逊相关系数:0.6(中等)

差异原因:

        因为余弦相似度没有考虑用户的平均评分习惯。用户A和用户B的平均评分都是3,但他们的评分模式有所不同。皮尔逊相关系数通过中心化处理,更好地反映了评分模式的一致性。

代码示例:

import numpy as np
from scipy.stats import pearsonr
# 用户评分数据
userA_ratings = [5, 4, 3, 2, 1]
userB_ratings = [4, 5, 2, 1, 3]
# 手动计算皮尔逊相关系数
def manual_pearson(x, y):
# 计算平均值
mean_x = np.mean(x)
mean_y = np.mean(y)
# 计算分子
numerator = np.sum((np.array(x) - mean_x) * (np.array(y) - mean_y))
# 计算分母
denominator = np.sqrt(np.sum((np.array(x) - mean_x)**2)) * np.sqrt(np.sum((np.array(y) - mean_y)**2))
return numerator / denominator
# 使用scipy计算
scipy_pearson, _ = pearsonr(userA_ratings, userB_ratings)
print(f"手动计算皮尔逊系数: {manual_pearson(userA_ratings, userB_ratings):.3f}")
print(f"Scipy计算皮尔逊系数: {scipy_pearson:.3f}")
# 计算余弦相似度
from sklearn.metrics.pairwise import cosine_similarity
cosine_sim = cosine_similarity([userA_ratings], [userB_ratings])[0][0]
print(f"余弦相似度: {cosine_sim:.3f}")

输出结果:

手动计算皮尔逊系数: 0.600
Scipy计算皮尔逊系数: 0.600
余弦相似度: 0.927​

3. 调整余弦相似度

        调整余弦相似度是针对余弦相似度的改进版本,它从每个评分中减去相应用户的平均评分,从而消除用户评分偏差。这是因为不同的用户可能有不同的评分习惯:有些用户倾向于打高分,有些用户则倾向于打低分。这种方法结合了余弦相似度和皮尔逊相关系数的优点,在实践中表现出更好的性能。

计算公式:

其中:

  • $r_{u,i}$ 是用户 $u$ 对物品 $i$ 的评分
  • $r_{u,j}$ 是用户 $u$ 对物品 $j$ 的评分
  • $\bar{r_u}$ 是用户 $u$ 的平均评分
  • $U$ 是同时对物品 $i$ 和 $j$ 评分的用户集合

评分过程推理:

假设我们有3个用户对3个物品的评分:

用户物品A物品B物品C平均分
用户15323.33
用户24212.33
用户33454.00

计算物品A和物品B的调整余弦相似度

第一步: 计算调整后的评分

  • 用户1: (5-3.33, 3-3.33) = (1.67, -0.33)
  • 用户2: (4-2.33, 2-2.33) = (1.67, -0.33)
  • 用户3: (3-4.00, 4-4.00) = (-1.00, 0.00)

第二步: 计算分子

  • 分子 = (1.67)(-0.33) + (1.67)(-0.33) + (-1.00)(0.00) = -0.55 - 0.55 + 0 = -1.10

第三步: 计算分母

  • 分母A = √(1.67² + 1.67² + (-1.00)²) = √(2.79 + 2.79 + 1.00) = √6.58 = 2.57
  • 分母B = √((-0.33)² + (-0.33)² + 0.00²) = √(0.11 + 0.11 + 0.00) = √0.22 = 0.47

第四步: 计算相似度

  • 相似度 = -1.10 / (2.57 × 0.47) = -1.10 / 1.21 ≈ -0.91

代码示例:

import numpy as np
import pandas as pd
def adjusted_cosine_similarity(item_i_ratings, item_j_ratings, user_means):
"""
计算两个物品之间的调整余弦相似度
参数:
item_i_ratings: 物品i的评分列表
item_j_ratings: 物品j的评分列表
user_means: 相应用户的平均评分列表
返回:
调整余弦相似度
"""
# 转换为numpy数组
ratings_i = np.array(item_i_ratings)
ratings_j = np.array(item_j_ratings)
means = np.array(user_means)
# 只考虑两个物品都被评分的用户
common_ratings = np.where((ratings_i > 0) & (ratings_j > 0))[0]
if len(common_ratings) < 2:
return 0  # 需要至少2个共同评分用户
ratings_i_common = ratings_i[common_ratings]
ratings_j_common = ratings_j[common_ratings]
means_common = means[common_ratings]
# 计算调整后的评分
adjusted_i = ratings_i_common - means_common
adjusted_j = ratings_j_common - means_common
# 计算分子和分母
numerator = np.sum(adjusted_i * adjusted_j)
denominator = np.sqrt(np.sum(adjusted_i**2)) * np.sqrt(np.sum(adjusted_j**2))
# 避免除以零
if denominator == 0:
return 0
return numerator / denominator
# 示例使用
itemA_ratings = [5, 4, 3]  # 三个用户对物品A的评分
itemB_ratings = [3, 2, 4]  # 三个用户对物品B的评分
user_means = [3.33, 2.33, 4.00]  # 三个用户的平均评分
# 计算余弦相似度
from sklearn.metrics.pairwise import cosine_similarity
cosine_sim = cosine_similarity([itemA_ratings], [itemB_ratings])[0][0]
print(f"余弦相似度: {cosine_sim:.3f}")
adj_cosine_sim = adjusted_cosine_similarity(itemA_ratings, itemB_ratings, user_means)
print(f"调整余弦相似度: {adj_cosine_sim:.3f}")

输出结果:

余弦相似度: 0.919
调整余弦相似度: -0.921

        通过结果看出两中评分的差异还是很大的,调整余弦相似度就是要消除评分偏差,比传统余弦相似度更能反映物品之间的真实相似性,特别适合物品数量少于用户数量的场景。

四、协同过滤的两种核心类型

        协同过滤主要分为两大类型:基于内存的方法和基于模型的方法。基于内存的方法直接使用整个用户-物品交互数据集进行预测,而基于模型的方法则先从数据中学习一个预测模型,再用这个模型进行预测。

1. 基于内存的方法

1.1 基于用户的协同过滤

  • 核心逻辑:找到与目标用户兴趣相似的用户群体,然后基于这个群体的偏好来预测目标用户可能喜欢的物品。
  • 方法说明:这种方法依赖于用户间的相似度计算,用户相似度计算后,选择最相似的K个用户作为邻居,然后基于邻居用户的评分进行加权平均来预测目标用户对未知物品的评分。

生活化例子:

        假设你和朋友小明都喜欢《星际穿越》《盗梦空间》《信条》这三部诺兰电影,且都打了5星。系统发现你们的观影偏好高度相似(相似度90%),而小明最近给《变形金刚》打了5星,那么系统就会把《变形金刚》推荐给你。

实现步骤:

第一步:构建用户-物品评分矩阵

假设有3个用户和4部电影,评分范围1-5(0表示未评分):

用户/电影星际穿越盗梦空间信条变形金刚
5550
小明5455
小红2320

第二步:计算用户相似度

        系统会对比你和其他用户的评分向量,计算“相似度分数”。最常用的方法是余弦相似度,可以理解为“两个用户偏好向量之间的夹角大小”——夹角越小,偏好越相似。

        在上面的例子中,你和小明的相似度远高于你和小红(接近90% vs 约30%)。

第三步:找到邻居用户并生成推荐

        选择与你最相似的K个用户(比如K=10),将他们喜欢但你未评分的物品,按相似度加权平均后推荐给你。

示例:计算用户相似度矩阵

def calculate_pearson_similarity_matrix(ratings_df):
"""
计算所有用户之间的皮尔逊相关系数矩阵
参数:
ratings_df: 用户-物品评分DataFrame
返回:
皮尔逊相似度矩阵DataFrame
"""
n_users = ratings_df.shape[1]  # 用户数量
similarity_matrix = np.zeros((n_users, n_users))
# 获取用户列表
users = ratings_df.columns.tolist()
# 计算每对用户之间的相似度
for i in range(n_users):
for j in range(i, n_users):  # 只需计算上三角矩阵
if i == j:
similarity_matrix[i, j] = 1.0  # 用户与自己的相似度为1
else:
user_i_ratings = ratings_df[users[i]].values
user_j_ratings = ratings_df[users[j]].values
similarity = pearson_similarity(user_i_ratings, user_j_ratings)
similarity_matrix[i, j] = similarity
similarity_matrix[j, i] = similarity  # 对称矩阵
# 转换为DataFrame
similarity_df = pd.DataFrame(
similarity_matrix,
index=users,
columns=users
)
return similarity_df
# 创建示例数据
ratings_data = {
'用户1': [5, 4, 0, 0, 3],
'用户2': [4, 0, 5, 0, 2],
'用户3': [0, 3, 4, 5, 0],
'用户4': [2, 0, 0, 4, 5],
'用户5': [0, 5, 3, 0, 4]
}
movies = ['电影A', '电影B', '电影C', '电影D', '电影E']
ratings_df = pd.DataFrame(ratings_data, index=movies)
# 计算皮尔逊相似度矩阵
pearson_sim_df = calculate_pearson_similarity_matrix(ratings_df)
print("皮尔逊相似度矩阵:")
print(pearson_sim_df)

输出结果:

皮尔逊相似度矩阵:
     用户1  用户2  用户3  用户4  用户5
用户1  1.0  1.0  0.0 -1.0  1.0        
用户2  1.0  1.0  0.0 -1.0 -1.0        
用户3  0.0  0.0  1.0  0.0 -1.0
用户4 -1.0 -1.0  0.0  1.0  0.0
用户5  1.0 -1.0 -1.0  0.0  1.0

1.2 基于物品的协同过滤

  • 核心逻辑:首先计算物品之间的相似度,然后根据用户历史喜欢的物品找到相似物品进行推荐。
  • 方法说明:这种方法的基本假设是,如果用户喜欢某个物品,那么他也很可能喜欢与这个物品相似的其他物品。基于物品的方法在实际应用中往往表现更好,因为物品之间的关系通常比用户之间的关系更加稳定,而且物品的数量通常少于用户数量,计算效率更高。

生活化例子:

        如果你买了《哈利波特与魔法石》,电商平台会推荐《哈利波特与密室》。这不是因为系统知道它们都是“奇幻小说”(基于内容的推荐),而是因为数据显示:购买《魔法石》的用户中,有80%也会购买《密室》——系统通过用户行为发现了物品之间的隐藏关联。

实现步骤:

第一步:构建物品-用户评分矩阵

以电影为行,用户为列:

电影小明小红
星际穿越552
盗梦空间543
信条552
变形金刚050

第二步:计算物品相似度

        分析哪些电影经常被同一批用户喜欢。例如,《星际穿越》和《信条》的评分向量高度相似(你和小明都打了5星,小红打了2星),因此它们的相似度很高。

第三步:生成推荐

        对于你喜欢的电影(如《星际穿越》),找出与其最相似的K部电影(如《信条》《奥本海默》),推荐给你。
示例:计算物品相似度矩阵

def calculate_adjusted_cosine_matrix(ratings_df):
"""
计算所有物品之间的调整余弦相似度矩阵
参数:
ratings_df: 用户-物品评分DataFrame(行:物品, 列:用户)
返回:
调整余弦相似度矩阵
"""
n_items = ratings_df.shape[0]  # 物品数量
items = ratings_df.index.tolist()
# 计算每个用户的平均评分
user_means = ratings_df.mean(axis=0)
# 初始化相似度矩阵
similarity_matrix = np.zeros((n_items, n_items))
# 计算每对物品之间的相似度
for i in range(n_items):
for j in range(i, n_items):  # 只需计算上三角矩阵
if i == j:
similarity_matrix[i, j] = 1.0  # 物品与自身的相似度为1
else:
item_i_ratings = ratings_df.iloc[i].values
item_j_ratings = ratings_df.iloc[j].values
sim = adjusted_cosine_similarity(
item_i_ratings,
item_j_ratings,
user_means.values
)
similarity_matrix[i, j] = sim
similarity_matrix[j, i] = sim  # 对称矩阵
# 转换为DataFrame
similarity_df = pd.DataFrame(
similarity_matrix,
index=items,
columns=items
)
return similarity_df
# 创建示例数据
ratings_data = {
'用户1': [5, 4, 0, 0, 3],
'用户2': [4, 0, 5, 0, 2],
'用户3': [0, 3, 4, 5, 0],
'用户4': [2, 0, 0, 4, 5],
'用户5': [0, 5, 3, 0, 4]
}
movies = ['电影A', '电影B', '电影C', '电影D', '电影E']
ratings_df = pd.DataFrame(ratings_data, index=movies)
# 计算调整余弦相似度矩阵
adj_cosine_sim_df = calculate_adjusted_cosine_matrix(ratings_df)
print("调整余弦相似度矩阵:")
print(adj_cosine_sim_df)

输出结果:

物品调整余弦相似度矩阵:
          电影A       电影B       电影C  电影D       电影E
电影A  1.000000  0.000000  0.000000  0.0  0.070364
电影B  0.000000  1.000000  0.552674  0.0  0.981455
电影C  0.000000  0.552674  1.000000  0.0  0.086630
电影D  0.000000  0.000000  0.000000  1.0  0.000000
电影E  0.070364  0.981455  0.086630  0.0  1.000000

1.3 两者的关键区别

维度基于用户的协同过滤基于物品的协同过滤
核心对象用户相似度物品相似度
适用场景用户少、物品多(如小众社区)物品少、用户多(如电商平台)
稳定性较差(用户偏好易变化)较好(物品属性相对稳定)
推荐解释性难(“和你相似的人喜欢”)易(“你喜欢的物品类似”)
计算复杂度高(用户增长快)低(物品更新慢)

2. 基于模型的方法

        通过机器学习算法从数据中学习一个预测模型。常见的模型包括矩阵分解、聚类模型、深度学习模型等。其中,矩阵分解是最为经典的模型方法,它将用户-物品评分矩阵分解为用户特征矩阵和物品特征矩阵的乘积,通过潜在特征向量来表示用户和物品。

        大模型的结合可以很好的解决新用户或新物品缺乏历史数据的问题,也正好解决了疑难的冷启动的问题。

示例:基于大语言模型的混合推荐系统

        示例结合了传统的协同过滤方法和现代的大语言模型技术。系统首先使用传统的用户-物品评分矩阵,然后通过大语言模型分析物品的文本描述来计算语义相似度,最终将两种相似度结合来生成更准确的推荐。

2.1 代码结构

2.1.1 数据准备

# 创建示例数据:用户对电影的评分
# 行代表用户,列代表电影,数值代表评分(0表示未评分)
ratings_data = {
'用户1': [5, 4, 3, 0, 0],
'用户2': [4, 5, 0, 2, 1],
'用户3': [3, 0, 4, 5, 2],
'用户4': [0, 3, 5, 4, 3],
'用户5': [2, 1, 0, 3, 4]
}
movies = ['电影A', '电影B', '电影C', '电影D', '电影E']
# 创建评分矩阵
ratings_df = pd.DataFrame(ratings_data, index=movies)
print("用户-电影评分矩阵:")
print(ratings_df)

意图说明:

  • 创建一个模拟的用户-电影评分数据集,用于演示推荐系统的工作原理
  • 使用0表示用户未观看或未评分的电影,这是推荐系统中常见的表示方法
  • 构建一个DataFrame结构,便于后续的数据处理和计算

2.1.2 文本相似度计算器

class TextSimilarityCalculator:
"""基于大模型的文本相似度计算器"""
def __init__(self, model_name='D:/modelscope/hub/models/sentence-transformers/all-MiniLM-L6-v2'):
# 初始化代码...
def encode_texts(self, texts):
# 编码文本...
def calculate_similarity(self, text1, text2):
# 计算两个文本的相似度...
def batch_similarity_matrix(self, texts):
# 批量计算相似度矩阵...

意图说明:

  • 创建一个专门用于计算文本相似度的类,封装了大语言模型的使用细节
  • 使用Sentence Transformer模型将文本转换为高维向量表示
  • 模型采用的本地路径,在前面的文章中,也用到了这个模型,已经下载到了本地
  • 通过计算向量间的余弦相似度来量化文本之间的语义相似性
  • 提供批量处理功能,提高计算效率


2.1.3 混合推荐系统

class HybridRecommender:
"""结合传统协同过滤和大模型的混合推荐系统"""
def __init__(self, ratings_df, text_model_name='D:/modelscope/hub/models/sentence-transformers/all-MiniLM-L6-v2'):
# 初始化代码...
def _precompute_item_embeddings(self):
# 预计算物品嵌入...
def calculate_semantic_similarity(self, item_id1, item_id2):
# 计算语义相似度...
def hybrid_similarity(self, item_id1, item_id2, alpha=0.7):
# 计算混合相似度...
def _calculate_cf_similarity(self, item_id1, item_id2):
# 计算协同过滤相似度...
def generate_recommendations(self, target_user_id, top_n=5, alpha=0.7):
# 生成推荐...
def _predict_rating(self, user_id, item_id, alpha):
# 预测评分...

意图说明:

  • 创于物品的协同过滤,使用皮尔逊相关系数计算物品相似度
  • 提供生建一个混合推荐系统,结合传统协同过滤和大语言模型的优势
  • 使用参数alpha控制两种方法的权重,实现灵活的混合策略
  • 预计算物品的文本嵌入,提高推荐时的计算效率
  • 实现基成推荐列表的功能,为目标用户预测对未评分物品的评分

2.2 输出结果

用户-电影评分矩阵:
     用户1  用户2  用户3  用户4  用户5
电影A    5    4    3    0    2
电影B    4    5    0    3    1
电影C    3    0    4    5    0
电影D    0    2    5    4    3
电影E    0    1    2    3    4
加载模型: D:/modelscope/hub/models/sentence-transformers/all-MiniLM-L6-v2
电影描述语义相似度矩阵:
[[1.0000004  0.78310543 0.8368864  0.7532436 ]
 [0.78310543 0.9999992  0.79229146 0.6913045 ]
 [0.8368864  0.79229146 0.9999998  0.70960337]
 [0.7532436  0.6913045  0.70960337 0.9999997 ]]

电影相似度: 0.791
加载模型: D:/modelscope/hub/models/sentence-transformers/all-MiniLM-L6-v2
推荐: 电影D, 预测评分: 2.10
推荐: 电影E, 预测评分: 1.95

2.3 核心算法

2.3.1 语义相似度计算

        系统使用大语言模型将物品的文本描述转换为高维向量,然后通过计算向量间的余弦相似度来量化物品之间的语义相似性。这种方法能够捕捉到传统协同过滤无法发现的深层语义关系。

2.3.2 混合相似度计算

        系统将传统的协同过滤相似度和大语言模型计算的语义相似度进行加权融合:

混合相似度 = α × 协同过滤相似度 + (1-α) × 语义相似度

2.3.3 评分预测

        对于目标用户未评分的物品,系统基于用户已评分的相似物品进行评分预测:

预测评分 = 用户平均评分 + ∑[相似度 × (评分 - 物品平均评分)] / ∑|相似度|

这种方法既考虑了用户的整体评分习惯,也考虑了物品的相对受欢迎程度。

2.3.4 基于大模型的相似度计算为推荐系统做了进一步的优化改进: 

  • 深度语义理解:能够理解内容的深层含义,而不仅仅是表面特征
  • 跨模态能力:可以处理文本、图像、音频等多种类型的数据
  • 解决冷启动:有效处理新用户和新物品的推荐问题
  • 增强可解释性:能够生成自然语言的推荐解释

3.  各自的适用场景

每种类型的协同过滤都有其适用场景和优缺点。

  • 基于用户的方法更适用于用户群体相对稳定、用户兴趣多样性较强的场景;
  • 基于物品的方法更适合物品数量相对较少、物品特征相对稳定的场景;
  • 而基于模型的方法则更适合大规模数据集和需要离线训练的场景。

五、协同过滤挑战与解决方案

1. 冷启动问题

  • 场景:新用户(无行为数据)、新物品(无交互记录)、新平台(无任何数据)
  • 解决方法:
    • 新用户:基于注册信息(年龄、性别)或热门物品推荐
    • 新物品:基于内容特征(如电影类型、导演)或人工标注
    • 混合推荐:结合基于内容的推荐(如“你喜欢科幻片,推荐《沙丘》”)

2. 数据稀疏性

  • 问题:用户-物品矩阵中99%以上的位置是0(用户很少评分)
  • 解决方法:
    • 降维技术:如矩阵分解(SVD),将高维稀疏矩阵压缩为低维稠密矩阵
    • 邻居选择优化:只考虑有共同评分的用户/物品计算相似度

3. 可扩展性

  • 问题:当用户或物品数量达百万级时,计算所有相似度变得极其缓慢
  • 解决方法:
    • 近似算法:如局部敏感哈希(LSH)快速查找相似用户/物品
    • 离线计算:提前预计算物品相似度,实时推荐时直接查询

六、经典应用场景

  • 电商平台:淘宝“猜你喜欢”、亚马逊“购买此商品的人还购买了”
  • 流媒体:Netflix电影推荐、Spotify歌曲推荐
  • 社交网络:Facebook好友推荐、LinkedIn职位推荐

七、总结

        协同过滤作为推荐系统的经典方法,在处理用户行为数据方面具有不可替代的价值。而大模型的出现为推荐系统带来了语义理解、内容生成和跨模态处理等新能力。两者的结合代表了推荐系统发展的新方向:

传统协同过滤的价值:

  • 在处理大量用户行为数据方面仍然有效
  • 算法相对简单,计算效率高
  • 在实际系统中经过长期验证

大模型的贡献:

  • 解决冷启动问题,处理新用户和新物品
  • 提供深度语义理解和跨模态能力
  • 增强推荐的可解释性和用户体验

        随着大模型技术的不断发展和优化,以及计算资源的更加普及,基于协同过滤和大模型的混合推荐系统将成为主流。这种系统不仅能够提供更准确的推荐,还能够提供更加人性化和可解释的推荐体验,真正实现懂你所需、荐你所想的个性化服务。

附录:基于模型的方法完整代码

import numpy as np
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import torch
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
# 创建示例数据:用户对电影的评分
# 行代表用户,列代表电影,数值代表评分(0表示未评分)
ratings_data = {
'用户1': [5, 4, 3, 0, 0],
'用户2': [4, 5, 0, 2, 1],
'用户3': [3, 0, 4, 5, 2],
'用户4': [0, 3, 5, 4, 3],
'用户5': [2, 1, 0, 3, 4]
}
movies = ['电影A', '电影B', '电影C', '电影D', '电影E']
# 创建评分矩阵
ratings_df = pd.DataFrame(ratings_data, index=movies)
print("用户-电影评分矩阵:")
print(ratings_df)
class TextSimilarityCalculator:
"""基于大模型的文本相似度计算器"""
def __init__(self, model_name='D:/modelscope/hub/models/sentence-transformers/all-MiniLM-L6-v2'):
"""
初始化文本相似度计算器
参数:
model_name: 预训练模型名称
- 'all-MiniLM-L6-v2': 轻量级通用模型
- 'all-mpnet-base-v2': 高质量通用模型
- 'multi-qa-mpnet-base-dot-v1': 问答优化模型
"""
self.model = SentenceTransformer(model_name)
print(f"加载模型: {model_name}")
def encode_texts(self, texts):
"""
将文本列表编码为向量表示
参数:
texts: 文本列表
返回:
文本向量矩阵
"""
return self.model.encode(texts, convert_to_tensor=True)
def calculate_similarity(self, text1, text2):
"""
计算两个文本之间的相似度
参数:
text1: 第一个文本
text2: 第二个文本
返回:
相似度分数 (0-1)
"""
# 编码文本
embeddings = self.encode_texts([text1, text2])
# 计算余弦相似度
similarity = cosine_similarity(
embeddings[0].cpu().numpy().reshape(1, -1),
embeddings[1].cpu().numpy().reshape(1, -1)
)[0][0]
return similarity
def batch_similarity_matrix(self, texts):
"""
计算文本集合的相似度矩阵
参数:
texts: 文本列表
返回:
相似度矩阵
"""
embeddings = self.encode_texts(texts)
similarity_matrix = cosine_similarity(embeddings.cpu().numpy())
return similarity_matrix
# 使用示例
text_calculator = TextSimilarityCalculator()
# 电影描述示例
movie_descriptions = [
"一部讲述黑客与反乌托邦系统斗争的赛博朋克惊悚片",
"一部设定在未来世界、科技先进的科幻冒险片",
"一部讲述两人在纽约坠入爱河的浪漫喜剧",
"一部以二战为背景的历史剧"
]
# 计算相似度矩阵
similarity_matrix = text_calculator.batch_similarity_matrix(movie_descriptions)
print("电影描述语义相似度矩阵:")
print(similarity_matrix)
# 计算特定文本对相似度
text1 = "一部关于人工智能和机器人的电影"
text2 = "一部探索人类与机器之间关系的电影"
similarity = text_calculator.calculate_similarity(text1, text2)
print(f"\n电影相似度: {similarity:.3f}")
print("=" * 50)
print("混合推荐系统")
print("=" * 50)
class HybridRecommender:
"""结合传统协同过滤和大模型的混合推荐系统"""
def __init__(self, ratings_df, text_model_name='D:/modelscope/hub/models/sentence-transformers/all-MiniLM-L6-v2'):
"""
初始化混合推荐系统
参数:
ratings_df: 用户-物品评分DataFrame
text_model_name: 文本编码模型名称
"""
self.ratings_df = ratings_df
self.text_calculator = TextSimilarityCalculator(text_model_name)
# 预计算物品文本特征
self.item_descriptions = {}  # 假设有物品描述数据
self.item_embeddings = self._precompute_item_embeddings()
def _precompute_item_embeddings(self):
"""预计算所有物品的文本嵌入"""
item_ids = self.ratings_df.index.tolist()
descriptions = [self.item_descriptions.get(item_id, "") for item_id in item_ids]
return self.text_calculator.encode_texts(descriptions)
def calculate_semantic_similarity(self, item_id1, item_id2):
"""计算两个物品的语义相似度"""
idx1 = self.ratings_df.index.get_loc(item_id1)
idx2 = self.ratings_df.index.get_loc(item_id2)
emb1 = self.item_embeddings[idx1].cpu().numpy()
emb2 = self.item_embeddings[idx2].cpu().numpy()
return cosine_similarity([emb1], [emb2])[0][0]
def hybrid_similarity(self, item_id1, item_id2, alpha=0.7):
"""
计算混合相似度(协同过滤 + 语义相似度)
参数:
item_id1: 物品1ID
item_id2: 物品2ID
alpha: 协同过滤权重 (1-alpha为语义相似度权重)
"""
# 计算传统协同过滤相似度(基于评分)
cf_similarity = self._calculate_cf_similarity(item_id1, item_id2)
# 计算语义相似度
semantic_similarity = self.calculate_semantic_similarity(item_id1, item_id2)
# 混合相似度
hybrid_sim = alpha * cf_similarity + (1 - alpha) * semantic_similarity
return hybrid_sim
def _calculate_cf_similarity(self, item_id1, item_id2):
"""计算基于评分的协同过滤相似度"""
ratings1 = self.ratings_df.loc[item_id1].values
ratings2 = self.ratings_df.loc[item_id2].values
# 只考虑共同评分的用户
common_ratings = np.where((ratings1 > 0) & (ratings2 > 0))[0]
if len(common_ratings)  0].index
for rated_item in rated_items:
similarity = self.hybrid_similarity(item_id, rated_item, alpha)
rating = self.ratings_df.loc[rated_item, user_id]
item_mean = self.ratings_df.loc[rated_item].mean()
numerator += similarity * (rating - item_mean)
denominator += abs(similarity)
if denominator == 0:
return user_mean
predicted_rating = user_mean + (numerator / denominator)
return max(1, min(5, predicted_rating))  # 确保评分在1-5范围内
# 使用示例
# 假设已有ratings_df和物品描述
hybrid_rec = HybridRecommender(ratings_df)
recommendations = hybrid_rec.generate_recommendations('用户1')
for item_id, rating in recommendations:
print(f"推荐: {item_id}, 预测评分: {rating:.2f}")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/908383.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

office2024安装教程(附安装包)Office 2024 专业增强版下载安装激活详细图文步骤

一、为啥推荐 Office 2024 专业增强版?(新手必看) 现在办公真离不开好用的套件,Office 2024 专业增强版比 2021、2019 这些老版本强太多了 —— 不管是上班族做数据报表、写项目方案,还是学生写毕业论文、做答辩 …

EMS 抗扰度在边缘计算产品电路设计的基本问题 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

20231326王荣盛《密码系统设计》第二周预习报告

20231326王荣盛《密码系统设计》第二周预习报告20231326王荣盛《密码系统设计》第二周预习报告 目录20231326王荣盛《密码系统设计》第二周预习报告学习内容《Windows C/C++ 加密解密实战》第3章《Windows C/C++ 加密解…

Gitflow 工作流程

代码版本如何控制,便于在工作中代码乱改,版本管理紊乱。写在前面 在工作场合实施 Git 的时候,有很多种工作流程可供选择,此时反而会让你手足无措。企业团队最常用的一些 Git 工作流程,包括 Centralized Workflow、…

魔改chromium真正通杀全网debugger检测

声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 目标网站 通过魔改chromium,做…

C#依赖注入

一、什么是依赖注入? 依赖指的是:当一个类(A)需要另一个类(B)的功能才能完成工作时,A 就 "依赖" 于 B。例如:OrderService需要用Logger记录日志,那么OrderService依赖于Logger。依赖注入的核心思想…

springboot手写源码总结

springboot手写源码总结先创建spring容器,然后将配置类(也就是启动类,因为上面有标注@ComponentScan和@Configuration注解)注册到spring容器中去,进行扫描。然后将spring容器绑定到servlet中,将servlet添加到tom…

完整教程:Docker Compose 一键启动多容器服务

完整教程:Docker Compose 一键启动多容器服务pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &q…

【截稿倒计时、高录用、稳检索】2025年教育创新与信息技术国际学术会议(EIIT 2025)

【高录用、稳检索】 2025年教育创新与信息技术国际学术会议 2025 International Conference on Educational Innovation and Information Technology (EIIT 2025) 教育、创新、信息科学相关主题方向均可投稿 *参会者现…

低代码 + AI 构建智慧校园系统:某高校宿舍报修平台的48小时构建全流程

低代码 + AI 构建智慧校园系统:某高校宿舍报修平台的48小时构建全流程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: &…

[MCP][07]logging和progress等功能说明

除了基础的Prompt、Resource和Tool概念,FastMCP还提供了以下功能:Sampling、Elicitation、Logging、Progress、Proxy、Middleware、Composition和Authentication功能前言 截至目前(2025年9月19日),除了基础的Prom…

端口命令

1、查询指定端口(如查询 8080 端口):netstat -ano | findstr "8080"结果说明:LISTENING 表示端口正在监听;最后一列数字是 进程 PID2、通过 PID 查对应进程(如 PID 为 1234):tasklist | findstr &qu…

Microsoft OLE漏洞致远程代码执行安全公告解析

微软发布安全公告3010060,披露Windows OLE组件远程代码执行漏洞。攻击者通过特制PowerPoint文件实施定向攻击,本文提供受影响环境、攻击向量及临时缓解方案(Fix it工具、UAC配置、EMET部署)的详细技术指导。セキュ…

写代码还是写提示词?——Prompt 工程是不是程序员的新技能树

过去二十年,程序员的核心技能几乎没变:学语言、写代码、调 bug。但是 AI 大模型的出现,正在悄悄改写这套逻辑。 有人开始疑惑:👉 “未来的程序员,还需要会写代码吗?”👉 “Prompt 工程(提示词工程)是不是新…

c-store发送dcm文件超时

错误代码:FellowOakDicom.Network.DicomAssociationRequestTimedOutException:“The association request timed out 3 times, waiting 5000ms each time for the association response等超时返回解决方案:首先要明白…

解码C语言模块化编程

一、模块化设计原则原则 说明 示例高内聚 模块内部功能紧密相关 将数学计算函数集中到 math_utils 模块低耦合 模块间依赖最小化(通过接口通信) 使用头文件声明接口,隐藏实现细节单一职责 每个模块只解决一个特定问…

redis存储漂流瓶信息

问题 比如漂流瓶的数据,都放在redis里,支持12小时过期,支持最大捡起数,支持重复捡取。 漂流了内容,有头像,昵称,内容(文字,语音),年龄,城市,过期时间,读取次数。 支持随机捡瓶子。 使用tp5需要怎么设计…

hashcat高效爆破Wi-Fi密码方法(比aircrack-ng快)

​ (tip:本文所有操作在个人测试环境下运行,请不要用于违法行为) 准备工具: 电脑 kali-linux-2025.2系统(4G内存以上) ----在aircrack爆破时,无线网络审计套件(aircrack-ng)作为内置模组组件常用于一体化流程爆破密…

更新到macOS Sequoia后,chrome无法用ip访问192.168.*

设置 -> 隐私与安全 -> 本地网络 开启chrome按钮 System Settings -> Privacy & Security -> Local Network

Typora标题自动显示序号,大纲中也显示序号

Typora标题自动显示序号,大纲中也显示序号 代码一:一级标题显示序号点击查看代码 /*************************************** Header Counters in TOC (目录中的标题计数器)**************************************/…