为了验证推荐系统中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数据库配置
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,
分批从数据库加载数据,变换为矩阵
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)
参数说明:
coo_matrix的功能特点
1 构建稀疏矩阵: coo_matrix允许您通过提供非零元素的位置和值来构建一个稀疏矩阵。
2 节省内存: 对于大部分元素为0的大矩阵来说,使用稀疏矩阵可以显著减少内存占用。3 高效操作: 稀疏矩阵提供了许多高效的矩阵运算,如加法、乘法等。
4 转换为其他格式: coo_matrix可以轻松转换为其他稀疏矩阵格式,如CSR(Compressed SparseRow)或CSC(Compressed Sparse Column)等。
vstack(垂直堆叠)是SciPy库中的函数,用于将多个稀疏矩阵垂直堆叠在一起形成一个新的稀疏矩阵。vstack函数通常用于将多个较小的稀疏矩阵合并成一个较大的矩阵,特别是在处理分批加载的数据时非常有用。
基本用法:
vstack(blocks, format=None, dtype=None)
参数:
blocks:一个包含多个稀疏矩阵的元组或列表,这些矩阵将被垂直堆叠。
format:可选参数,指定输出矩阵的格式,默认为输入矩阵的格式。
dtype:可选参数,指定输出矩阵中元素的数据类型。
vstack的功能
# 分批加载数据
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权重
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的主要特性
model = AlternatingLeastSquares(
factors=50,
regularization=0.01,
iterations=20
)
参数说明
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}")