推荐算法页面recommendation.py
python
import django
# 导入Django模块,用于初始化Django环境
os.environ.setdefault('DJANGO_SETTINGS_MODULE','去哪儿旅游数据分析推荐系统.settings')
# 设置环境变量,指定Django项目的配置文件路径
# 'DJANGO_SETTINGS_MODULE'是Django识别的环境变量名
# 告诉Django使用哪个配置文件来加载项目设置
django.setup()
# 初始化Django环境
# 这行代码让Django加载配置文件、连接数据库、准备ORM
# 之后才能使用Django的模型(如TravelInfo)来查询数据库
from app.models import TravelInfo
# 从app应用中导入TravelInfo模型类
# TravelInfo对应数据库中的景点信息表,包含景点名称、评论等数据
# 以下是被注释掉的示例数据,展示了用户评分数据的格式
# user_ratings = {
# "Edward": {"南山文化旅游区": 5}, # 用户Edward给南山文化旅游区打了5分
# "EdwardD": {"南山文化旅游区": 5, "三亚蜈支洲岛旅游区": 2}, # 用户EdwardD有两个评分
# "newEdward" # 新用户,还没有评分
# }
# ============================================================================
def getUser_ratings():
# 定义函数:从数据库中获取用户评分数据
# 返回值是一个字典,格式为 {用户ID: {景点名称: 评分, ...}, ...}
user_ratings = {}
# 初始化一个空字典,用于存储所有用户的评分数据
for travel in TravelInfo.objects.all():
# 遍历数据库中的所有景点记录
# TravelInfo.objects.all() 返回所有景点对象的查询集
comments = json.loads(travel.comments)
# 将当前景点的comments字段从JSON字符串解析为Python列表
# travel.comments 在数据库中是JSON字符串,存储了该景点的所有用户评论
# 例如: '[{"userId":1,"content":"很好","score":5}, ...]'
for com in comments:
# 遍历当前景点的每一条评论
# com是一个字典,包含评论的详细信息
try:
com['userId']
# 尝试访问评论中的'userId'字段
# 这行代码本身没有赋值,只是用来检查字段是否存在
except:
continue
# 如果评论中没有'userId'字段(比如爬取的评论中没有用户ID)
# 则跳过这条评论,不进行处理
if user_ratings.get(com['userId'],-1) == -1:
# 检查这个用户是否已经在user_ratings字典中
# user_ratings.get(key, default) 如果key存在返回对应的值,否则返回default
# 这里返回-1表示用户不存在
user_ratings[com['userId']] = {travel.title: com['score']}
# 如果用户不存在,创建新条目
# 键是用户ID,值是一个字典,包含当前景点名称和评分
# travel.title是景点名称,com['score']是评分
else:
user_ratings[com['userId']][travel.title] = com['score']
# 如果用户已存在,在用户的评分字典中添加当前景点的评分
# 格式如: user_ratings[1]["故宫"] = 5
return user_ratings
# 返回构建好的用户评分字典
# ============================================================================
def user_bases_collaborative_filtering(user_id, user_ratings, top_n=3):
# 定义基于用户的协同过滤推荐函数
# 参数说明:
# user_id: 目标用户的ID,要为这个用户生成推荐
# user_ratings: 所有用户的评分数据,由getUser_ratings()返回
# top_n: 选取相似度最高的N个用户,默认值为3
# 返回值:推荐给目标用户的景点列表
# 获取目标用户的评分数据
target_user_ratings = user_ratings[user_id]
# 从所有用户评分字典中取出目标用户的评分数据
# 格式如: {"故宫": 5, "长城": 4, ...}
# 初始化一个字典,用于保存其他用户与目标用户的相似度得分
user_similarity_scores = {}
# 格式: {其他用户ID: 相似度得分, ...}
# 将目标用户的评分转化为numpy数组
target_user_ratings_list = np.array([
rating for _, rating in target_user_ratings.items()
])
# 列表推导式,提取目标用户对所有景点的评分值
# target_user_ratings.items() 返回键值对,我们只需要值(评分)
# 结果如: [5, 4, 0, 3] (0表示该景点没有评分)
# np.array() 将列表转换为NumPy数组,便于数学计算
# 计算目标用户与其他用户之间的相似度得分
for user, ratings in user_ratings.items():
# 遍历所有用户及其评分数据
# user是用户ID,ratings是该用户的评分字典
if user == user_id:
# 如果是目标用户自己
continue
# 跳过,不计算自己与自己的相似度
# 将其他用户的评分转化为numpy数组
user_ratings_list = np.array([ratings.get(item, 0) for item in target_user_ratings])
# 重要:这里只考虑目标用户评分过的景点
# 对于目标用户评分过的每个景点,获取当前用户的评分
# 如果当前用户没有评分过该景点,用0填充
# 结果是一个与target_user_ratings_list长度相同的数组
# 计算余弦相似度
similarity_score = cosine_similarity([user_ratings_list], [target_user_ratings_list])[0][0]
# cosine_similarity() 是sklearn中的函数,计算两个向量的余弦相似度
# 参数需要是二维数组,所以用[vector]包装
# 返回值是一个二维数组,[0][0]取出相似度值
# 相似度范围[-1,1],越接近1表示越相似
user_similarity_scores[user] = similarity_score
# 将计算出的相似度存入字典
# 对用户相似度得分进行降序排序
sorted_similar_user = sorted(user_similarity_scores.items(), key=lambda x: x[1], reverse=True)
# user_similarity_scores.items() 返回 [(用户1,相似度1), (用户2,相似度2), ...]
# sorted() 排序,key=lambda x: x[1] 指定按相似度排序
# reverse=True 表示降序(相似度高的排前面)
# 结果如: [('user3', 0.95), ('user5', 0.87), ('user2', 0.76), ...]
# 选择 TOP N 个相似用户喜欢的景点作为推荐结果
recommended_items = set()
# 初始化一个空集合,用于存放推荐的景点
# 使用集合可以自动去重
for similar_user, _ in sorted_similar_user[:top_n]:
# 遍历相似度最高的前N个用户
# sorted_similar_user[:top_n] 取前N个元素
# similar_user是用户ID,_是相似度(这里不需要)
recommended_items.update(user_ratings[similar_user].keys())
# 将这个相似用户评分过的所有景点名称加入推荐集合
# user_ratings[similar_user].keys() 返回该用户评分过的景点名称列表
# update() 方法将多个元素加入集合
# 过滤掉目标用户已经评分过的景点
recommended_items = [item for item in recommended_items if item not in target_user_ratings]
# 列表推导式,遍历推荐集合中的每个景点
# 只保留那些不在目标用户评分字典中的景点
# 因为用户已经评分过的景点不需要再推荐
return recommended_items
# 返回最终的推荐景点列表
# ============================================================================
if __name__ == '__main__':
# Python的特殊用法:当这个文件被直接运行时,执行下面的代码
# 如果这个文件被其他文件导入,则不执行
user_id = 1
# 设置目标用户ID为1
# 在实际系统中,这个ID可能来自当前登录用户
user_ratings = getUser_ratings()
# 调用getUser_ratings()函数,从数据库获取所有用户的评分数据
recommended_items = user_bases_collaborative_filtering(user_id, user_ratings)
# 调用协同过滤函数,为user_id生成推荐列表
# 使用默认的top_n=3
代码功能总结
| 函数 | 作用 | 输入 | 输出 |
|---|---|---|---|
| getUser_ratings | 从数据库构建用户-评分矩阵 | 无(读取数据库) | 用户评分字典 |
| user_bases_collaborative_filtering | 基于用户的协同过滤推荐 | 用户ID、评分数据、相似用户数 | 推荐景点列表 |
整体流程:
-
初始化Django环境,连接数据库
-
从TravelInfo表的comments字段解析出所有用户的评分
-
构建用户-景点评分矩阵
-
为目标用户找到最相似的N个用户
-
从相似用户喜欢的景点中筛选出目标用户未评过的
-
返回推荐列表