表设计
# 用户表
class UserInfo(models.Model):
username = models.CharField(max_length=32,unique=True,verbose_name="用户名")
password = models.CharField(max_length=64)
# 物品表
class Movies(models.Model):
name = models.CharField(max_length=255,verbose_name="电影名称")
movie_score = models.FloatField(verbose_name="评分(未评分的为0)")
# 评分表
class UserScore(models.Model):
movie = models.ForeignKey(to="Movies",verbose_name="电影",on_delete=models.CASCADE)
user = models.ForeignKey(to="UserInfo",verbose_name="用户",on_delete=models.CASCADE)
movie_score = models.FloatField(verbose_name="评分")
整理数据集
user_id = request.GET.get("user_id")
outList = [] # 二维数组
userIds = [] # 用户主键数组
goodsIds = [] # GOODS主键数组
# 遍历用户 - 整理数据结构成二维数组
for user_obj in models.UserInfo.objects.order_by("id"):
userIds.append(user_obj.id) # 储存用户ID (找到用户主键)
goodsIds = [] # 储存GOODS ID (找到物品主键)
innerList = [] # 储存特征数值 (array二维对象)
# 遍历数据
for movie_obj in models.Movies.objects.order_by("id"):
# 储存GOODS ID
goodsIds.append(movie_obj.id)
try:
# 获取用户评分
movie_score = models.UserScore.objects.get(user_id=user_obj.id, movie_id=movie_obj).movie_score
except:
# 如果没有评分的物品为0
movie_score = 0
# 储存特征数值
innerList.append(movie_score)
outList.append(innerList)
# 转换array对象
user_ratings = np.array(outList)
# 计算推荐ID 5个
tj_goods_list = user_similarity_check(user_id,user_ratings, userIds, goodsIds, 5)
# 数据库中查找
QuerySetData = models.Movies.objects.filter(pk__in=tj_goods_list)
# 未评分的为0
for J in QuerySetData:
try:
J.movie_score = models.UserScore.objects.get(user_id=user_id, movie_id=J.id).movie_score
except:
J.movie_score = 0
计算相似度,推荐商品ID
# 计算用户相似度进行推荐物品ID
def user_similarity_check(user_id,user_ratings_array,userIds,goodsIds,count):
import random
"""
:param user_id: 当前用户ID
:param user_ratings_array: np.array 二维数组 对象
user_ratings = np.array([
[5, 3, 0, 0, 2], # 用户主键ID 1 的评分
[4, 0, 0, 0, 1], # 用户主键ID 2 的评分
[物品主键1, 物品主键2, 物品主键3, 物品主键4, 物品主键5],
])
:param userIds: 用户主键ID 对应每行的ID
:param goodsIds: 物品主键ID 对应每列的ID
:param count : 返回多少个推荐商品
:return: 返回数组 ,包含推荐商品ID
"""
# 计算特征相似度
user_similarity = cosine_similarity(user_ratings_array)
# 匹配当前用户ID 在索引里面的位置 在下面查询后直接使用
user_index = np.where(np.array(userIds) == int(user_id))[0][0]
# 查询出最相似的索引用户排序情况
user_tj_list = np.argsort(-user_similarity[user_index])
# 获取除了自身的最近的ID
tj_user_id = user_tj_list[1]
# 推荐GOODS
recommended_items = user_ratings_array[tj_user_id]
# 取出大于0的GOODS 的ID 进行推荐
matching_indexes = np.where(recommended_items > 0)[0]
matching_goodsIds = [goodsIds[index] for index in matching_indexes]
return random.sample(matching_goodsIds,count)
# 计算评分相似度进行推荐物品ID
def item_similarity_check(user_id,goods_ratings_array,userIds,goodsIds,count):
"""
:param goods_ratings_array: np.array 二维数组 对象
user_ratings = np.array([
[5, 3, 0, 0, 2], # 用户主键ID 1 的评分
[4, 0, 0, 0, 1], # 用户主键ID 2 的评分
[物品主键1, 物品主键2, 物品主键3, 物品主键4, 物品主键5],
])
:param userIds: 用户主键ID 对应每行的ID
:param goodsIds: 物品主键ID 对应每列的ID
:param count : 返回多少个推荐商品
:return: 返回数组 ,包含推荐商品ID
"""
# 计算物品相似度
item_similarity = cosine_similarity(goods_ratings_array.T)
# 取出该用户对所有评分的物品 List
user_index = np.where(np.array(userIds) == int(user_id))[0][0]
this_user_list = goods_ratings_array[user_index]
# 取出该用户评分为0的物品 索引列表 [5, 4, 0, 0, 2] => [2, 3]
unrated_items = np.where(this_user_list == 0)[0]
# 物品之间的相似度 该用户对物品的评分 ====> 计算两个数组的点积(即矩阵乘法)
top = np.dot(item_similarity, goods_ratings_array[user_index])
# 包含所有物品的预测评分的数组(或向量),其中每个元素表示该物品的预测评分。
# 包含每个物品的相似度之和的数组(或向量),其中每个元素表示每个物品与其他所有物品的相似度之和
down = np.sum(item_similarity, axis=1)
# 计算用户对未评分物品的兴趣度
scores = top / down
# 计算用户对未评分物品的兴趣度
top_items = [x for x in sorted(zip(unrated_items, scores[unrated_items]), key=lambda x: x[1], reverse=True)]
# 获取索引
tj_goods_id_list = [x[0] for x in top_items[0:count]]
matching_elements = [goodsIds[index] for index in tj_goods_id_list]
return matching_elements