推荐召回中ALS(交替最小二乘法)算法验证

文章目录

  • 需求
  • 流程设计
    • 步骤1: 数据准备
    • 步骤2: 模型训练
    • 步骤3: 评估指标选择
    • 步骤4: 性能评估
  • 代码实现
    • 导入依赖
    • Mysql获取数据
    • 分批加载到矩阵
      • 目标
      • coo_matrix
      • vstack
    • bm25_weight
    • 模型训练
  • 测试
  • 评估
  • 完整代码

需求

为了验证推荐系统中ALS(交替最小二乘)算法的召回效果以及离线数据推荐的效果,我们需要进行一系列的实验步骤。这些步骤包括数据准备、模型训练、评估指标的选择以及最终的性能评估

流程设计

步骤1: 数据准备

  • 加载数据:从MySQL数据库中加载用户-物品评分数据。
    确保数据集足够大,并且用户和物品都有足够的评分记录。
  • 划分数据集:将数据集划分为训练集和测试集。可以采用80%的数据作为训练集,剩余20%作为测试集。
  • 对于每个用户,从其评分记录中随机选择一部分作为测试集。
  • 构建用户-物品评分矩阵:使用训练集构建用户-物品评分矩阵。确保评分矩阵中用户ID和物品ID都减去了1,以适应从0开始的索引。

步骤2: 模型训练

  • 初始化ALS模型:
    使用AlternatingLeastSquares类初始化ALS模型。
  • 设置模型的超参数,例如因子数量(factors)、正则化系数(regularization)和迭代次数(iterations)。
  • 应用BM25权重:
    可以选择性地应用BM25权重来优化用户-物品评分矩阵,以增强稀疏数据的效果。
  • 训练模型:
    使用训练集中的用户-物品评分矩阵训练ALS模型。

步骤3: 评估指标选择

  • 定义评估指标:
    选择合适的评估指标来衡量推荐系统的性能,常见的评估指标包括精确度(Precision)、召回率(Recall)、F1分数等。
  • 在本例中,我们将主要关注召回率(Recall),因为它衡量的是推荐系统能够成功找到相关物品的能力。

步骤4: 性能评估

  • 离线数据推荐:
    对于测试集中的每个用户,使用训练好的模型进行推荐。
  • 根据每个用户的测试集记录来评估推荐结果。
  • 计算召回率:
    对于每个用户,计算推荐结果中实际出现的测试集物品比例。
    平均所有用户的召回率,得到整体的召回率。
  • 结果分析:
    分析召回率的结果,评估ALS模型在推荐系统中的有效性。
    可以尝试不同的超参数组合,以寻找最佳的模型配置。

代码实现

导入依赖

import pandas as pd
import numpy as np
from sqlalchemy import create_engine
from scipy.sparse import coo_matrix, vstack
from implicit.als import AlternatingLeastSquares
from implicit.nearest_neighbours import bm25_weight

Mysql获取数据

# MySQL数据库配置
DATABASE_TYPE = 'mysql'
DBAPI = 'test'
USERNAME = 'test'
PASSWORD = 'test'
HOST = '127.0.0.1'  # 或者是数据库服务器的IP地址
PORT = 3306
DATABASE = 'test'


# 创建数据库连接
engine = create_engine(f"{DATABASE_TYPE}+{DBAPI}://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DATABASE}")
print(engine)
# SQL查询语句
query = "SELECT * FROM user_rate"

分批加载到矩阵

目标

使用coo_matrix构建一个稀疏矩阵,足够容纳user-item,
分批从数据库加载数据,变换为矩阵

coo_matrix

 batch_user_item_matrix = coo_matrix((batch_df['score'], (batch_df['uid'] - 1, batch_df['mediaid'] - 1)), shape=(n_users, n_items))
        print("用户-物品评分",batch_user_item_matrix)

coo_matrix函数是SciPy库中的一部分,用于创建一个基于坐标格式(Coordinate
Format)的稀疏矩阵。这种类型的矩阵非常适合从零开始构建矩阵,尤其是在需要逐个元素填充的情况下。

coo_matrix((data, (row, col)), shape=None, dtype=None, copy=False)
参数说明:

  • data:一个一维数组,包含非零元素的值。
  • row:一个一维数组,与data对应,表示每个非零元素所在的行索引。
  • col:一个一维数组,与data对应,表示每个非零元素所在的列索引。
  • shape:可选参数,表示矩阵的形状,默认情况下,它会根据row和col的最大值自动确定。
  • dtype:可选参数,表示矩阵中元素的数据类型。
  • copy:可选参数,布尔值,表示是否复制输入数据。

coo_matrix的功能特点
1 构建稀疏矩阵: coo_matrix允许您通过提供非零元素的位置和值来构建一个稀疏矩阵。
2 节省内存: 对于大部分元素为0的大矩阵来说,使用稀疏矩阵可以显著减少内存占用。

3 高效操作: 稀疏矩阵提供了许多高效的矩阵运算,如加法、乘法等。
4 转换为其他格式: coo_matrix可以轻松转换为其他稀疏矩阵格式,如CSR(Compressed SparseRow)或CSC(Compressed Sparse Column)等。

vstack

vstack(垂直堆叠)是SciPy库中的函数,用于将多个稀疏矩阵垂直堆叠在一起形成一个新的稀疏矩阵。vstack函数通常用于将多个较小的稀疏矩阵合并成一个较大的矩阵,特别是在处理分批加载的数据时非常有用。
基本用法:

vstack(blocks, format=None, dtype=None)
参数:
blocks:一个包含多个稀疏矩阵的元组或列表,这些矩阵将被垂直堆叠。
format:可选参数,指定输出矩阵的格式,默认为输入矩阵的格式。
dtype:可选参数,指定输出矩阵中元素的数据类型。

vstack的功能

  • 垂直堆叠 将多个稀疏矩阵沿着垂直方向堆叠在一起。
  • 兼容不同格式 vstack支持多种稀疏矩阵格式,如COO、CSR、CSC等。
    数据类型转换:
  • 通过dtype参数指定输出矩阵的数据类型。
  • 灵活的格式转换 可以在堆叠后转换输出矩阵的格式
# 分批加载数据
def load_data_in_batches(engine, query, batch_size):
    # 确定用户和物品的总数
    n_users = pd.read_sql_query("SELECT MAX(uid) AS max_user_id FROM user_rate", engine)['max_user_id'][0] + 1
    n_items = pd.read_sql_query("SELECT MAX(mediaid) AS max_item_id FROM user_rate", engine)['max_item_id'][0] + 1
    print("矩阵",n_users,n_items)
    # 初始化一个空的稀疏矩阵
    user_item_matrix = None
    
    # 分批处理数据
    offset = 0
    while True:
        # 获取当前批次的数据
        batch_df = pd.read_sql_query(f"{query} LIMIT {batch_size} OFFSET {offset}", engine)
        print("分批数据",batch_df)
        # 如果没有更多的数据,则停止循环
        if batch_df.empty:
            break
        #if offset>20: # 测试使用
        #    break
        # 创建当前批次的用户-物品评分矩阵
        batch_user_item_matrix = coo_matrix((batch_df['score'], (batch_df['uid'] - 1, batch_df['mediaid'] - 1)), shape=(n_users, n_items))
        print("用户-物品评分",batch_user_item_matrix)
        # 将当前批次的矩阵添加到总矩阵中
        if user_item_matrix is None:
            user_item_matrix = batch_user_item_matrix
        else:
            user_item_matrix = vstack([user_item_matrix, batch_user_item_matrix])
        
        # 更新偏移量
        offset += batch_size
    
    # 将coo_matrix转换为csr_matrix
    user_item_matrix = user_item_matrix.tocsr()
    print(user_item_matrix)
    return user_item_matrix

user_item_matrix.tocsr()
参照 常见稀疏矩阵格式及转换

bm25_weight

# 应用BM25权重
user_item_matrix = bm25_weight(user_item_matrix.T).T
print("user_item_matrix BM2",user_item_matrix)

bm25_weight函数被用来对用户-物品评分矩阵进行加权处理,以提高推荐质量。这里两次使用转置操作的原因在于bm25_weight函数的输入期望是物品-用户评分矩阵,而不是用户-物品评分矩阵。

第一次转置 (user_item_matrix.T):

原始的user_item_matrix是一个用户-物品评分矩阵,其中行代表用户,列代表物品。
user_item_matrix.T将矩阵转置,使行代表物品,列代表用户。这样就变成了一个物品-用户评分矩阵,这符合bm25_weight函数的输入要求。

调用bm25_weight函数:

bm25_weight函数期望输入是一个物品-用户评分矩阵,即转置后的user_item_matrix.T。 这个函数会对输入矩阵进行BM25加权处理,这是一种文本检索领域常用的技术,用于改善文档排名。在推荐系统中,它可以提高推荐的质量。

第二次转置 (bm25_weight(user_item_matrix.T).T)

经过bm25_weight处理后,输出仍然是一个物品-用户评分矩阵。
再次转置是为了将结果转换回原始的用户-物品评分矩阵格式,即行代表用户,列代表物品

模型训练

# 初始化ALS模型
model = AlternatingLeastSquares(factors=50, regularization=0.01, iterations=20)
print("user_item_matrix bgn fit")
# 训练模型
model.fit(user_item_matrix)
print("user_item_matrix end fit",user_item_matrix)
user_item_matrix = user_item_matrix.tocsr()
print("tocsr",user_item_matrix)

AlternatingLeastSquares是implicit库中的一个类,用于实现交替最小二乘(Alternating Least Squares,> ALS)算法。
ALS是一种广泛应用于协同过滤推荐系统的方法,主要用于解决用户-物品评分矩阵中的缺失值问题,从而生成用户对未评分物品的预测评分或推荐。

AlternatingLeastSquares的主要特性

  • 交替更新:
    ALS算法通过交替更新用户因子矩阵和物品因子矩阵来最小化预测评分与实际评分之间的平方误差。
  • 正则化:
    ALS算法通常包含正则化项以避免过拟合。
  • 隐式反馈:
    implicit库中的AlternatingLeastSquares特别设计用于处理隐式反馈数据,即用户的行为数据(如点击、浏览等),而不是显式的评分数据。
  • 可扩展性:
    implicit库利用了稀疏矩阵运算,使得ALS算法能够高效地处理大规模数据集。
model = AlternatingLeastSquares(
      factors=50, 
      regularization=0.01, 
      iterations=20
      )

参数说明

  • factors:用户和物品的因子数量。
  • regularization:正则化系数,用于控制模型复杂度。
  • iterations:迭代次数,即交替更新用户和物品因子的轮数

测试

recommend方法参数
user_id:要为其生成推荐的用户ID。
user_vector:用户-物品评分矩阵中对应用户的行向量。
N:要返回的推荐物品数量。
filter_already_liked_items:是否过滤掉用户已经评分过的物品

 测试用户1 的推荐
user_id = 1  # 示例用户ID
# 使用user_item_matrix的行索引来获取用户向量
user_vector = user_item_matrix[user_id - 1]
print("用户向量",user_vector)
# 获取用户推荐 过滤已经点击的
recommendations = model.recommend(user_id - 1, user_vector, N=10, filter_already_liked_items=True)
print("推荐",recommendations)

评估

在推荐系统中,通常需要评估模型的性能。常用的评估指标包括精确率、召回率、F1分数等

from implicit.evaluation import precision_at_k, recall_at_k

# 假设test_user_item_matrix是测试集的用户-物品评分矩阵
precision = precision_at_k(model, user_item_matrix, test_user_item_matrix, K=10)
recall = recall_at_k(model, user_item_matrix, test_user_item_matrix, K=10)

print(f"Precision@10: {precision:.4f}")
print(f"Recall@10: {recall:.4f}")

完整代码

import pandas as pd
import numpy as np
from sqlalchemy import create_engine
from scipy.sparse import coo_matrix, vstack
from implicit.als import AlternatingLeastSquares
from implicit.nearest_neighbours import bm25_weight

# MySQL数据库配置
DATABASE_TYPE = 'mysql'
DBAPI = 'pymysql'
USERNAME = 'test'
PASSWORD = 'test'
HOST = '127.0.0.1'  # 或者是数据库服务器的IP地址
PORT = 3306
DATABASE = 'test'


# 创建数据库连接
engine = create_engine(f"{DATABASE_TYPE}+{DBAPI}://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DATABASE}")
print(engine)
# SQL查询语句
query = "SELECT * FROM user_rate"

# 分批加载数据
def load_data_in_batches(engine, query, batch_size):
    # 确定用户和物品的总数
    n_users = pd.read_sql_query("SELECT MAX(uid) AS max_user_id FROM user_rate", engine)['max_user_id'][0] + 1
    n_items = pd.read_sql_query("SELECT MAX(mediaid) AS max_item_id FROM user_rate", engine)['max_item_id'][0] + 1
    print("矩阵",n_users,n_items)
    # 初始化一个空的稀疏矩阵
    user_item_matrix = None
    
    # 分批处理数据
    offset = 0
    while True:
        # 获取当前批次的数据
        batch_df = pd.read_sql_query(f"{query} LIMIT {batch_size} OFFSET {offset}", engine)
        print("分批数据",batch_df)
        # 如果没有更多的数据,则停止循环
        if batch_df.empty:
            break
        if offset>20:
            break
        # 创建当前批次的用户-物品评分矩阵
        batch_user_item_matrix = coo_matrix((batch_df['score'], (batch_df['uid'] - 1, batch_df['mediaid'] - 1)), shape=(n_users, n_items))
        print("用户-物品评分",batch_user_item_matrix)
        # 将当前批次的矩阵添加到总矩阵中
        if user_item_matrix is None:
            user_item_matrix = batch_user_item_matrix
        else:
            user_item_matrix = vstack([user_item_matrix, batch_user_item_matrix])
        
        # 更新偏移量
        offset += batch_size
    
    # 将coo_matrix转换为csr_matrix
    user_item_matrix = user_item_matrix.tocsr()
    print(user_item_matrix)
    return user_item_matrix

# 设置批处理大小
batch_size = 10  # 每次处理1000个评分记录

# 加载数据并构建用户-物品评分矩阵
user_item_matrix = load_data_in_batches(engine, query, batch_size)

# 应用BM25权重
user_item_matrix = bm25_weight(user_item_matrix.T).T
print("user_item_matrix BM2",user_item_matrix)
# 初始化ALS模型
model = AlternatingLeastSquares(factors=50, regularization=0.01, iterations=20)
print("user_item_matrix bgn fit")
# 训练模型
model.fit(user_item_matrix)
print("user_item_matrix end fit",user_item_matrix)
user_item_matrix = user_item_matrix.tocsr()
print("tocsr",user_item_matrix)
# 获取用户推荐
user_id = 1  # 示例用户ID
# 使用user_item_matrix的行索引来获取用户向量
user_vector = user_item_matrix[user_id - 1]
print("用户向量",user_vector)

#recommendations = model.recommend(user_id - 1, user_vector, N=10)
# 获取用户推荐 过滤已经点击的
recommendations = model.recommend(user_id - 1, user_vector, N=10, filter_already_liked_items=True)

print("推荐",recommendations)
#recommendations = model.recommend(user_id - 1, user_item_matrix[user_id - 1], N=10)

# 输出推荐结果
item_ids, scores = recommendations
for item_id, score in zip(item_ids, scores):
    print(f"Item ID: {item_id + 1}, Score: {score:.12e}")

你可能感兴趣的:(算法,最小二乘法,机器学习,推荐算法,python)