一、什么是基于用户的协同过滤推荐系统
基于用户的协同过滤算法是一种在推荐系统中广泛应用的算法,它主要依据用户之间的相似性来为目标用户提供推荐,以下是其详细介绍:
基本原理
- 该算法认为,具有相似兴趣爱好的用户可能会对相同或相似的物品有偏好。通过分析用户对不同物品的行为数据(如评分、点击、购买等),找到与目标用户兴趣相似的其他用户,然后将这些相似用户喜欢的物品推荐给目标用户
二、创建数据库、数据表
1、安装msql
参考 :
MySQL安装(保姆级教程)_mysql安装教程-优快云博客^v102^pc_search_result_base9&utm_term=%E5%AE%89%E8%A3%85mysql&spm=1018.2226.3001.4187
2、安装navicat
Navicat——安装使用(图文详解)-优快云博客^v102^pc_search_result_base9&spm=1018.2226.3001.4187
3、创建数据库、数据表
(1)创建用户行为数据表
CREATE TABLE user_behavior (
id INT NOT NULL AUTO_INCREMENT COMMENT 'ID',
user_id VARCHAR(255) NOT NULL COMMENT '用户ID',
image_id VARCHAR(255) NOT NULL COMMENT '图片ID',
action VARCHAR(255) NOT NULL COMMENT '用户行为: 点击图片、点赞图片、制作同款、保存图片',
count INT NOT NULL DEFAULT 1 COMMENT '次数,默认为1',
image_type INT NOT NULL COMMENT '系统=1,用户=2',
create_time DATETIME NOT NULL COMMENT '创建时间',
PRIMARY KEY (id)
);
(2)创建推荐结果表
CREATE TABLE recommendation_results (
id INT NOT NULL AUTO_INCREMENT COMMENT 'ID',
user_id VARCHAR(255) NOT NULL COMMENT '用户ID',
image_id VARCHAR(255) NOT NULL COMMENT '图片ID',
image_type INT NOT NULL COMMENT '图片类型',
create_time DATETIME NOT NULL COMMENT '创建时间',
PRIMARY KEY (id)
);
4、生成模拟数据
import mysql.connector
import random
import string
from datetime import datetime
# 记录开始时间
start_time = datetime.now()
# 数据库连接配置
# 数据库配置信息字典,需替换为实际的数据库连接信息
db_config = {
# 数据库用户名
'user':'user',
# 数据库用户密码
'password': '123456',
# 数据库主机地址及端口号
'host': '127.0.0.1',
'port': 3306,
# 要连接的数据库名称
'database': 'image_recommendation',
# 当出现警告时是否抛出异常
'raise_on_warnings': True
}
# 连接到数据库
conn = mysql.connector.connect(**db_config)
cursor = conn.cursor()
# 模拟数据插入
num_records = 10000 # 要插入的记录数量
actions = ["点击图片", "点赞图片", "制作同款", "保存图片"]
image_types = [1, 2]
for _ in range(num_records):
# 生成 0 到 50 之间的随机整数
random_num = random.randint(0, 100)
# 拼接字符串
user_id = f"user_{random_num}"
# 生成 0 到 50 之间的随机整数
random_num1 = random.randint(0, 1000)
# 拼接字符串
image_id = f"image_{random_num1}"
action = random.choice(actions)
count = 1
image_type = 2
create_time = datetime.now()
query = """
INSERT INTO user_behavior (user_id, image_id, action, count, image_type, create_time)
VALUES (%s, %s, %s, %s, %s, %s)
"""
values = (user_id, image_id, action, count, image_type, create_time)
cursor.execute(query, values)
# 提交事务并关闭连接
conn.commit()
cursor.close()
conn.close()
print(f"已成功插入 {num_records} 条模拟数据到 user_behavior 表中。")
# 记录结束时间
end_time = datetime.now()
# 计算时间差
elapsed_time = end_time - start_time
# 提取秒数
elapsed_seconds = int(elapsed_time.total_seconds())
print(f"用时: {elapsed_seconds} 秒")
三、代码
定时运行,每天进行一次协同过滤的推荐
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
from sqlalchemy import create_engine
import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
# 记录开始时间
start_time = datetime.datetime.now()
# 推荐的topN
img_top_num = 20
user_top_num = 20
# 数据库配置信息字典,需替换为实际的数据库连接信息
db_config = {
# 数据库用户名
'user':'user',
# 数据库用户密码
'password': '123456',
# 数据库主机地址及端口号
'host': '127.0.0.1',
'port': 3306,
# 要连接的数据库名称
'database': 'image_recommendation',
# 当出现警告时是否抛出异常
'raise_on_warnings': True
}
# 推荐的方法
def run_recommendation():
try:
# 创建数据库连接
engine = create_engine(
f"mysql+pymysql://{db_config['user']}:{db_config['password']}@{db_config['host']}/{db_config['database']}")
# 读取 user_behavior 表
query = "SELECT user_id, image_id, action, count, image_type FROM user_behavior"
user_behavior_df = pd.read_sql(query, engine)
except Exception as e:
print(f"数据库连接或查询出错: {e}")
raise
# 为不同行为分配权重
action_weights = {
'点击图片': 1,
'点赞图片': 3,
'制作同款': 4,
'保存图片': 2
}
# 根据行为权重和行为次数计算得分
user_behavior_df['score'] = user_behavior_df.apply(
lambda row: row['count'] * action_weights.get(row['action'], 0), axis=1)
# 数据预处理:将用户行为转换为用户 - 物品交互矩阵
user_item_matrix = user_behavior_df.pivot_table(index='user_id',
columns='image_id',
values='score', fill_value=0)
# 计算用户相似度矩阵
user_similarity_matrix = cosine_similarity(user_item_matrix)
# 将相似度矩阵转换为 DataFrame
user_similarity_df = pd.DataFrame(user_similarity_matrix, index=user_item_matrix.index,
columns=user_item_matrix.index)
# 生成推荐结果
def generate_recommendations(user_id, user_similarity_df, user_item_matrix, top_n=20):
"""
根据目标用户、用户相似度矩阵和用户-物品交互矩阵生成推荐结果。
:param user_id: 目标用户的ID
:param user_similarity_df: 用户相似度矩阵的DataFrame
:param user_item_matrix: 用户-物品交互矩阵的DataFrame
:param top_n: 要获取的相似用户数量,默认为20
:return: 推荐的图片ID列表
"""
try:
# 获取目标用户的相似用户
similar_users = user_similarity_df[user_id].sort_values(ascending=False)[1:top_n + 1]
# 获取相似用户喜欢的物品
similar_users_items = user_item_matrix.loc[similar_users.index]
# 计算推荐分数
recommendations = similar_users_items.mean(axis=0).sort_values(ascending=False)
# 过滤掉用户已经交互过的物品
user_interacted_items = user_item_matrix.loc[user_id]
recommendations = recommendations[user_interacted_items == 0]
return recommendations.index.tolist()
except Exception as e:
print(f"生成推荐结果时出错: {e}")
return []
# 为每个用户生成推荐结果
recommendation_results = []
for user_id in user_item_matrix.index:
recommended_items = generate_recommendations(user_id, user_similarity_df, user_item_matrix)
recommendation_results.append({
'user_id': user_id,
'image_id': recommended_items,
'image_type': 2, # 假设推荐的图片类型为系统图片
'create_time': pd.Timestamp.now()
})
# 将推荐结果转换为 DataFrame
recommendation_results_df = pd.DataFrame(recommendation_results)
# 截取每个 user_id 对应的 image_id 列表的前 20 个
recommendation_results_df['image_id'] = recommendation_results_df['image_id'].apply(lambda x: x[:top_num])
# 将 image_id 列转换为字符串,因为数据库可能不支持直接存储列表
recommendation_results_df['image_id'] = recommendation_results_df['image_id'].apply(lambda x: ','.join(x))
try:
# 将推荐结果存储到 recommendation_results 表
recommendation_results_df.to_sql('recommendation_results', engine, if_exists='replace', index=False)
print("推荐结果已成功存储到 recommendation_results 表中。")
except Exception as e:
print(f"存储推荐结果时出错: {e}")
# 记录结束时间
end_time = datetime.datetime.now()
# 计算时间差
elapsed_time = end_time - start_time
# 提取秒数
elapsed_seconds = int(elapsed_time.total_seconds())
print(f"用时: {elapsed_seconds} 秒")
if __name__ == "__main__":
scheduler = BlockingScheduler()
# 设置每天运行一次,这里设置为每天凌晨0点运行,你可以根据需要调整时间
scheduler.add_job(run_recommendation, 'cron', hour=0)
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
pass