吴恩达机器学习 第三课 week2 推荐算法(上)

news2025/2/2 7:48:50

目录

01 学习目标

02 推荐算法

2.1 定义      

2.2 应用

2.3 算法

03 协同过滤推荐算法

04 电影推荐系统

4.1 问题描述

4.2 算法实现

05 总结


01 学习目标

     (1)了解推荐算法

     (2)掌握协同过滤推荐算法(Collaborative Filtering Recommender Algorithm)原理

     (3)利用协同过滤算法实现“电影推荐系统”

02 推荐算法

2.1 定义      

      推荐算法是信息过滤系统中的一种技术,旨在预测用户对未接触过的物品的喜好程度,并据此向用户推荐相应的物品。

2.2 应用

     推荐系统广泛应用于电商、社交媒体、音视频平台、新闻资讯等领域,可以提升用户体验、增加用户黏性和促进内容发现。

2.3 算法

      推荐算法大致可以分为以下几类:

03 协同过滤推荐算法

      下面基于一个生活场景来理解协同过滤算法的推荐逻辑。

      假设小强在上午11:30打开饱了么外卖APP搜索附近的菜馆,小强只在APP上进行一次评分,且APP有家最近上架的新菜馆“老狼大盘鸡”。小强进入APP最先看到的会是哪家菜馆呢?我们来算一下!

      假设下表中为该APP的全部数据(表中?表示未评过分或系统无法归类的菜馆): 

基于表中数据,可以提取以下数组(“0”替换“?”):

       菜品特征矩阵(值:0~1):

\textbf{X}_{n\times k}=\begin{bmatrix} 0.03 &0 &1 \\ 0.91& 0.01 & 0.01\\ 0.02& 1 &0.01 \\ 0.95 & 0.01 &0.01 \\ 0&0 & 0 \end{bmatrix}

       用户评分矩阵:

\textbf{Y}_{n\times m}=\begin{bmatrix} 3.5 &0 &0 \\ 4.8& 4.7 & 0\\ 4.3& 0 &5.0 \\ 5.0 & 4.9 &0 \\ 0&4.7 & 0 \end{bmatrix}

       评分判断矩阵(已评为1、未评为0):

\textbf{R}_{n\times m}=\begin{bmatrix} 1 &0 &0 \\ 1& 1 & 0\\ 1& 0 &1 \\ 1 & 1 &0 \\ 0&1 & 0 \end{bmatrix}

        此外,再构造一个用户参数矩阵W和用户参数向量b

\textbf{W}_{m\times k}=\begin{bmatrix} w_{11} &w_{12} &w_{13} \\ w_{21}& w_{22} & w_{23}\\ w_{31}& w_{32} &w_{33} \\ w_{41} & w_{42} &w_{43} \\ w_{51}&w_{52} & w_{53} \end{bmatrix} 

\textbf{b}_{1\times m}=\begin{bmatrix} b_{11} &b_{12}&b_{13} \end{bmatrix}

       由以上5个矩阵,可以构造出预测用户评分的一般式如下:

\textbf{Y}=\textbf{R}*(\textbf{X}\cdot \textbf{W}^T+\textbf{b})=\frac{1}{2}\sum_{j=0}^{n-1}\sum_{i=0}^{m-1}R^{(i,j)}*(W^{(j)}\cdot X^{(i)}+b^{(j)}-Y^{(i,j)})^2

式中,参数阵W和b采用梯度下降法计算得到,同时为防止参数过拟合,成本函数增加正则项,如下所示:

J(\textbf{W},\textbf{b},\textbf{X})=\textbf{Y}+\frac{\lambda }{2}\sum_{i=0}^{m-1}\sum_{t=0}^{k}(X_t^{(i)})^2+\frac{\lambda }{2}\sum_{j=0}^{n-1}\sum_{t=0}^{k}(W_t^{(j)})^2

       由于部分菜馆(老狼大盘鸡)的特征未知,因此增加了X的正则项。饱了么APP会根据成本最小原则预测出参数W和b及特征X,进而得到每位用户对不同菜馆的预测分数。最后预测出的小强的评分高低排序后,依次进行推荐,如下:

       计算结果表明,口碑最好且“小强”没评过分(可能没吃过)的“洛馍村家常菜”排在最前面;而“老狼大盘鸡”是新上的菜馆,其排名竟然是第二,这可能是饱了么的常客“小红”的评论发挥了作用;第三名是“小强”曾经给过高分的“幺妹川菜馆”。完整代码如下:

# 导包
import numpy as np
import tensorflow as tf
from tensorflow import keras

# 数据准备
X = np.array([[0.03, 0, 1], [0.91, 0.01, 0.01], [0.02, 1, 0.01], [0.95, 0.01, 0.01], [0, 0, 0]])
Y = np.array([[3.5, 0, 0], [4.8, 4.7, 0], [4.3, 0, 5], [5, 4.9, 0], [0, 4.7, 0]])
R = np.array([[1, 0, 0], [1, 1, 0], [1, 0, 1], [1, 1, 0], [0, 1, 0]])
label_ = ['老味道湘菜馆',
          '周口大盘鸡',
          '幺妹川菜馆',
          '洛馍村家常菜',
          '老狼大盘鸡']


# 定义归一化函数、成本函数
def normalizeRatings(Y, R):

    Ymean = (np.sum(Y*R,axis=1)/(np.sum(R, axis=1)+1e-12)).reshape(-1,1)
    Ynorm = Y - np.multiply(Ymean, R) 
    return(Ynorm, Ymean)


def cofi_cost_func(X, W, b, Y, R, lambda_):
    """
    Returns the cost for the content-based filtering
    Args:
      X (ndarray (num_movies,num_features)): matrix of item features
      W (ndarray (num_users,num_features)) : matrix of user parameters
      b (ndarray (1, num_users)            : vector of user parameters
      Y (ndarray (num_movies,num_users)    : matrix of user ratings of movies
      R (ndarray (num_movies,num_users)    : matrix, where R(i, j) = 1 if the i-th movies was rated by the j-th user
      lambda_ (float): regularization parameter
    Returns:
      J (float) : Cost
    """
    error = tf.linalg.matmul(X, tf.transpose(W)) + b - Y
    j = tf.boolean_mask(error, tf.cast(R, tf.bool)) ** 2
    J = 0.5 * tf.reduce_sum(j) + (lambda_ / 2) * (tf.reduce_sum(X **2) + tf.reduce_sum(W **2))
    
    return J


# 归一化处理
Ynorm, Ymean = normalizeRatings(Y, R)

# 定义模型
n, m = Y.shape
k =3

tf.random.set_seed(1234)
W = tf.Variable(tf.random.normal((m, k), dtype=tf.float64), name='W')
X = tf.Variable(tf.random.normal((n, k), dtype=tf.float64), name='X')
b = tf.Variable(tf.random.normal((1, m), dtype=tf.float64), name='b')

optimizer = keras.optimizers.Adam(learning_rate=0.005)

# 训练模型
iterations = 200
lambda_ = 1
for iter in range(iterations):
    with tf.GradientTape() as tape:
        cost = cofi_cost_func(X, W, b, Ynorm, R, lambda_)

    grads = tape.gradient(cost, [X, W, b])

    optimizer.apply_gradients(zip(grads, [X, W, b]))
    if iter %20 == 0:
        print(f'第{iter}次迭代的成本为:{cost.numpy()}')

# 预测分数
y = np.matmul(X, np.transpose(W)) + b
y_m = y + Ymean    # 恢复数值
pred = y_m[:,1]    # 选择小强的结果
ix = tf.argsort(pred, direction='DESCENDING')  # 降序排列

# 推荐
for i in range(len(ix)):
    print(f'top{i +1}:{label_[ix[i]]},预测评分:{pred[ix[i]]:0.2f}')

       协同过滤(Collaborative Filtering, CF)中的“协同”二字,其核心意义在于“合作”或“协同工作”,“协同”本质是通过分析用户群或物品群之间的共同行为模式,来推断和预测单个用户的潜在喜好,从而实现个性化推荐。在推荐系统领域,这种“协同”体现在算法利用大量用户的行为数据(如评分、购买历史、浏览记录等),通过分析用户之间的共同偏好或者物品之间的相似性,来实现对用户可能感兴趣但尚未直接接触的物品的推荐。

具体来说,协同过滤算法分为两大类:

  1. 用户协同过滤(User-based Collaborative Filtering):在这种方法中,“协同”意味着算法寻找与目标用户兴趣相似的其他用户群体。算法分析这些相似用户喜欢的物品,并基于这些相似用户的偏好来推荐物品给目标用户。这里,用户之间的“协同”体现在他们的共同兴趣和行为模式上。

  2. 物品协同过滤(Item-based Collaborative Filtering):在物品协同过滤中,“协同”的概念体现为算法识别出经常被相同用户喜欢的物品集合,即使这些用户之间可能没有直接的相似性。换句话说,如果用户A喜欢物品X和Y,用户B也喜欢物品X,那么就可以推断用户B可能也会喜欢物品Y。这里,物品之间的“协同”是基于它们被共同评价或消费的模式。

04 电影推荐系统

4.1 问题描述

      GroupLens  是明尼苏达大学双城分校计算机科学与工程系的一个研究实验室,专注于推荐系统、在线社区、移动和无处不在技术、数字图书馆和本地地理信息系统等领域。

      我们从GroupLens网站的 MovieLens 栏目下载电影数据集,用于构建“电影推荐系统”。

4.2 算法实现

     (1)导入所需模块

import numpy as np
import tensorflow as tf
from tensorflow import keras
from recsys_utils import *

recsys_utils模块内有数据读取函数load_precalc_params_smallload_ratings_small、load_Movie_List_pd以及归一化函数normalizeRatings 

      (2)数据读取

# 读取数据
X, W, b, num_movies, num_features, num_users = load_precalc_params_small()
Y, R = load_ratings_small()
# 读取电影信息并提取名称列
movieList, movieList_df = load_Movie_List_pd()

print("Y", Y.shape, "R", R.shape)
print("X", X.shape)
print("W", W.shape)
print("b", b.shape)
print("num_features", num_features)
print("num_movies",   num_movies)
print("num_users",    num_users)
print("movieList:\n",movieList[:5])
print("movieList_df:\n",movieList_df[:5])

       运行以上代码,结果如下:

    

(原始数据集包含由600名用户对9000部电影进行的评价。为了专注于2000年以后的电影,我们将数据集的规模缩小至包含443名用户和4778部电影。该数据集在0.5到5的范围内对电影进行评分,以0.5的步长递增) 

     (3)定义成本函数

def cofi_cost_func_v(X, W, b, Y, R, lambda_):
    """
    Returns the cost for the content-based filtering
    Vectorized for speed. Uses tensorflow operations to be compatible with custom training loop.
    Args:
      X (ndarray (num_movies,num_features)): matrix of item features
      W (ndarray (num_users,num_features)) : matrix of user parameters
      b (ndarray (1, num_users)            : vector of user parameters
      Y (ndarray (num_movies,num_users)    : matrix of user ratings of movies
      R (ndarray (num_movies,num_users)    : matrix, where R(i, j) = 1 if the i-th movies was rated by the j-th user
      lambda_ (float): regularization parameter
    Returns:
      J (float) : Cost
    """
    j = (tf.linalg.matmul(X, tf.transpose(W)) + b - Y)*R
    J = 0.5 * tf.reduce_sum(j**2) + (lambda_/2) * (tf.reduce_sum(X**2) + tf.reduce_sum(W**2))
    return J

tf.linalg.matmul(X, tf.transpose(W)) 是一个使用 TensorFlow 库的矩阵乘法函数,其中 XW 是两个张量(tensor),tf.transpose(W) 表示对张量 W 进行转置) 

      (4)目标用户数据提取

      假设推荐目标用户是Tony,Tony的历史评分如下(我们手动添加):

my_ratings = np.zeros(num_movies)          #  Initialize my ratings

# 手动添加Tony的评分
my_ratings[2700] = 5   # Toy Story 3 (2010)
my_ratings[2609] = 2   # Persuasion (2007)
my_ratings[929]  = 5   # Lord of the Rings: The Return of the King, The
my_ratings[246]  = 5   # Shrek (2001)
my_ratings[2716] = 3   # Inception
my_ratings[1150] = 5   # Incredibles, The (2004)
my_ratings[382]  = 2   # Amelie (Fabuleux destin d'Amélie Poulain, Le)
my_ratings[366]  = 5   # Harry Potter and the Sorcerer's Stone (a.k.a. Harry Potter and the Philosopher's Stone) (2001)
my_ratings[622]  = 5   # Harry Potter and the Chamber of Secrets (2002)
my_ratings[988]  = 3   # Eternal Sunshine of the Spotless Mind (2004)
my_ratings[2925] = 1   # Louis Theroux: Law & Disorder (2008)
my_ratings[2937] = 1   # Nothing to Declare (Rien à déclarer)
my_ratings[793]  = 5   # Pirates of the Caribbean: The Curse of the Black Pearl (2003)
# 已评分电影的索引
my_rated = [i for i in range(len(my_ratings)) if my_ratings[i] > 0]

# 将Tony的评分及相应的布尔数组添加至原数据中
Y = np.c_[my_ratings, Y]
R = np.c_[(my_ratings != 0).astype(int), R]

print("\n(New user)Tony's ratings:\n")
for i in range(len(my_ratings)):
    if my_ratings[i] > 0 :
        print(f'Rated {my_ratings[i]} for  {movieList_df.loc[i,"title"]}')

("my_rated = [i for i in range(len(my_ratings)) if my_ratings[i] > 0]": range(len(my_ratings)) 会生成一个从0 len(my_ratings)-1 的整数序列,如果 my_ratings[i]大于0,那么i 就会被添加到 my_rated 列表中

my_ratings != 0my_ratings 中不等于0的数转为true,等于0的数转为false(布尔数组),astype(int) 将该布尔数组转换为整数数组(0和1)然后用np.c_[] 将两个布尔数组按列合并)

      运行以上代码,结果如下:

      (5)数据归一化

Ynorm, Ymean = normalizeRatings(Y, R)

      (6)定义模型

num_movies, num_users = Y.shape
num_features = 100

# 采用tf.Variable 初始化参数
tf.random.set_seed(1234) # for consistent results
W = tf.Variable(tf.random.normal((num_users,  num_features),dtype=tf.float64),  name='W')
X = tf.Variable(tf.random.normal((num_movies, num_features),dtype=tf.float64),  name='X')
b = tf.Variable(tf.random.normal((1,          num_users),   dtype=tf.float64),  name='b')

# 设置优化器、学习率
optimizer = keras.optimizers.Adam(learning_rate=1e-1)

      (7)训练模型

iterations = 200
lambda_ = 1
for iter in range(iterations): 
    # 使用TensorFlow的GradientTape记录用于计算成本的操作
    with tf.GradientTape() as tape:

        # Compute the cost
        cost_value = cofi_cost_func_v(X, W, b, Ynorm, R, lambda_)

    # 使用梯度记录器自动获取可训练变量相对于损失的梯度。
    grads = tape.gradient( cost_value, [X,W,b] )

    # 通过更新变量的值来进行一次梯度下降,以使损失函数达到最小值。
    optimizer.apply_gradients( zip(grads, [X,W,b]) )

    # 打印进度
    if iter % 20 == 0:
        print(f"Training loss at iteration {iter}: {cost_value:0.1f}")

      运行以上代码,结果如下:

   

      (8)电影推荐

# 计算概率
p = np.matmul(X.numpy(), np.transpose(W.numpy())) + b.numpy()
# 归一化恢复
pm = p + Ymean
# 提取Tony的数据
my_predictions = pm[:,0]
# sort predictions返回降序索引
ix = tf.argsort(my_predictions, direction='DESCENDING')

# 推荐Tony未评价过的电影(从预测评分top17的电影中挑选)
for i in range(17):
    j = ix[i]
    if j not in my_rated:
        print(f'Predicting rating {my_predictions[j]:0.2f} for movie {movieList[j]}')

# 测试比对user评分的真实值与预测值
print('\n\nOriginal vs Predicted ratings:\n')
for i in range(len(my_ratings)):
    if my_ratings[i] > 0:
        print(f'Original {my_ratings[i]}, Predicted {my_predictions[i]:0.2f} for {movieList[i]}')

       运行以上代码,结果如下:

       上面的代码实现了两个功能:一是向Tony推荐了他从未评分的电影,二是将Tony评过分的13部电影分数与预测分数进行了对比,可以发现,如果考虑四舍五入的话,预测分数与Tony的评分完全一致。

05 总结

     (1)协同过滤算法的原理类似于多元线性回归,包括数据处理、定义模型、拟合参数及预测这4个关键步骤,相较于人工神经网络的“黑箱子”计算,协同过滤算法的计算过程更易理解。

     (2) 在协同过滤算法处理大批量数据时,采用tensorflow的张量计算和GradientTape可以迅速实现梯度下降,可以大幅提升计算效率。

     (3)不同的工程师设计的同类算法,可能推荐结果并不一致,这可能引出道德或伦理问题,比如某些平台会优先推荐利润率大而不是最适合用户的商品。

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

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

相关文章

正则表达式之三剑客grep

正则表达式匹配的是文本内容,linux的文本三剑客 都是针对文本内容 grep 过滤文本内容 sed 针对文本内容进行增删改查 awk 按行取列 文本三剑客都是按行进行匹配。 grep grep 的作用就是使用正则表达式来匹配文本内容 选项: -m …

vivado SLR

描述 超级逻辑区(SLR)是包含在堆叠硅中的单个FPGA芯片 互连(SSI)设备。堆叠式硅互连(SSI)技术使用无源硅 具有微凸块和硅通孔(TSV)的内插器,用于组合多个FPGA管芯 切片&a…

最长考拉兹序列

题目: 考虑如下定义在正整数集上的迭代规则: n n/2 (若n为偶数) n 3n1 (若n为奇数) 从13开始,可以迭代生成如下的序列: 13 40 20 10 5 16 8 4 2 1 可以看出这个序列(从13…

实时语音翻译软件哪个好?多语言实时沟通无负担

众所周知,英语是国际交流的共同语言。无论是跨国商务洽谈还是学术研讨,英语的流畅使用至关重要。 然而,语言的障碍依然存在,这时一款高效的英语语音翻译软件就显得尤为关键。它们能够即时转换语言,让我们的对话无国界…

跨境电商系列02:跨境电商的本质,是一场现代文明的“侵x入”吗

作者|夏虫(题图:中国龙) 公号,数据虫巢(ID: blogchong) “ 不知道有没有人想过一个问题,海出电商市场是增量的没问题,那为何是跨境电商的模式呢?所谓跨境电商,一定是存在商品流动&a…

pytest测试框架pytest-rerunfailures插件重试失败用例

Pytest提供了丰富的插件来扩展其功能,介绍下插件pytest-rerunfailures ,用于在测试用例失败时自动重新运行这些测试用例。 pytest-rerunfailures官方显示的python和pytest版本限制: Python 3.8pytest 7.2 或更新版本 此插件可以通过以下可…

《计算机英语》Unit2 Operating System and Computer Architecture 操作系统和计算机构造

SectionA Operating System操作系统 不同操作系统 批处理操作系统(Batch Processing Operating System) 分时操作系统(Time Sharing Operating System) 实时操作系统(Real Time Operating System) 个人操作系统(Personal Operating System) 网络操作系统(NOS, Network Operati…

【Vue3组件】分享一下自己写的简约风格评论区组件

代码比较简单,方便大家二次开发,旨在快速提供基础的样式模板,自行迭代定制 预览 简介 通用评论组件 组件功能 此组件旨在创建一个具备嵌套回复能力的通用评论区域,适用于构建动态、互动性强的用户讨论场景。 接收数据结构 组件通…

运营管理和服务支撑阶段

我前面的所有设备都部署好了,现在就需要运营管理和服务支撑 遇到问题了迅速解决,避免风险扩大 我们也可以给客户提供上面的服务,提高客户的预警能力,安全风险处理能力 我们不仅提供设备,还提供服务 我们公司成立了安…

如何选择服务器?快解析能搭建私人服务器吗?

随着网络的发展,搭建私人服务器逐渐成为网络达人们的热门选择,比如建立私人性质的博客、论坛、FTP、个人网站、服务器集群等。通过源搭建私人服务器,就可以将很多资源分享到网络上进行信息共享。随之而来的是服务器市场不断扩大,在…

马尔可夫聚类算法

马尔可夫聚类算法(Markov Clustering Algorithm,MCL)是一种用于图聚类的算法,广泛应用于生物信息学、社交网络分析、推荐系统等领域。 其核心思想是模拟随机游走过程,通过迭代地扩散和收缩图上的概率分布来识别图中的…

Java基础的重点知识-01-基础

文章目录 开发前言Java语言开发环境入门程序说明常量变量和数据类型数据类型转换运算符方法解析 开发前言 常用DOS命令 Java语言的初学者,学习一些DOS命令,会非常有帮助。DOS是一个早期的操作系统,现在已经被Windows系统取代,对于…

【mysql】建库

通过命令建库: CREATE DATABASE database_name; 如果是用Workbench:

React+TS前台项目实战(十六)-- 全局常用组件Pagination封装

文章目录 前言Pagination组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 [PC端&手机端] 总结 前言 在上篇文章中,我们封装了表格组件Table,本文则继续封装配套使用的分页器组件。想看Table表格组件的,可自行查看全局常用组件Tab…

【pytorch04】创建Tensor

numpy中的数据创建tensor 数据已经在numpy中了,将numpy中的数据转到tensor中来,因为我们将使用tensor在GPU上进行加速运算 从NUMPY导入的FLOAT其实是DOUBLE类型 list中的数据创建tensor FloatTensor()和大写的Tensor()接收的是shape(即数据的…

敏捷开发笔记(第7章节)--什么是敏捷设计

目录 1:PDF上传链接 7.1: 软件出了什么错 7.2: 设计的臭味--腐化软件的气味 7.2.1: 什么激化了软件的腐化 7.2.2: 敏捷团体不允许软件腐化 7.3: “copy”程序 1: 初始设计 2: 需求在变化 3: 得寸进尺 4: 期望变化 7.3.1: “copy”程序的敏捷设计 7.3.2:…

【职场人】职场故事:与邀功精的共舞

在我的职业生涯中,我遇到过一位特别引人注目的同事,我们都叫他李经理。他的工作能力并不差,但他有一个习惯,那就是喜欢邀功。他的这种习惯,不仅让我印象深刻,也让我在合作中学会了不少东西。 恶心的四件事 …

MySQL学习笔记-进阶篇-视图和存储过程

四、视图和存储过程 视图 存储过程 基本语法 创建 CREATE PROCEDURE ([参数列表]) BEGIN --SQL END; 调用 CALL 存储过程名([参数列表]) 查看 --查看指定数据库的存储过程及状态信息 SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SHCEMA…

AI-智能体

什么是 AI 智能体? 「AI 智能体」这个术语并没有真正被定义,对智能体究竟是什么也存在很多的争议。 AI 智能体可以定义为「一个被赋予行动能力的 LLM(通常在 RAG 环境中进行函数调用),以便在环境中对如何执行任务做出…

第一次接触Swing

学习java版的HslCommunication发现使用的是Swing,所以了解了一下~ 了解: Swing是Java的标准库(Java Foundation Classes, JFC)的一部分,用于构建桌面应用程序的图形用户界面(GUI)。它是Java AWT…