Skip to content

Commit

Permalink
多路召回实现
Browse files Browse the repository at this point in the history
  • Loading branch information
BlackTea-c committed Mar 16, 2024
1 parent 03a2303 commit a90aaa7
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 44 deletions.
5 changes: 3 additions & 2 deletions moiveRe/moiveReApp/admin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from django.contrib import admin

# Register your models here.
from .models import Question,Rating,Tag
from .models import Question,Rating,Tag,UserProfile

admin.site.register(Question)
admin.site.register(Rating)
admin.site.register(Tag)
admin.site.register(Tag)
admin.site.register(UserProfile)
29 changes: 29 additions & 0 deletions moiveRe/moiveReApp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.utils import timezone
from django.core.validators import MinValueValidator, MaxValueValidator
from django.contrib.auth.models import User
from datetime import datetime, timedelta

class Tag(models.Model):
name = models.CharField(max_length=200)
Expand All @@ -27,6 +28,7 @@ class Question(models.Model):

likes = models.PositiveIntegerField(default=0)
liked_by = models.ManyToManyField(User, blank=True, related_name='liked_questions')
clicks = models.PositiveIntegerField(default=0)
def __str__(self):
return f"{self.question_text} - {self.img.url}"

Expand Down Expand Up @@ -60,4 +62,31 @@ def __str__(self):
return f"{self.question.question_text} - {self.value}"


class Userinterests(models.Model):
name = models.CharField(max_length=100, unique=True)

def __str__(self):
return self.name


class UserProfile(models.Model):
# 与用户关联的一对一字段,这里假设你使用了Django内置的User模型
user = models.OneToOneField(User, on_delete=models.CASCADE)
interests = models.ManyToManyField(Userinterests, related_name='interested_users')
liked_items = models.ManyToManyField(Question, blank=True, related_name='liked_users')
click_items = models.ManyToManyField(Question, blank=True, related_name='clicked_users')


def __str__(self):
return self.user.username + "'s Profile"

@classmethod
def get_user_profile(cls, user):
# 根据用户获取或创建用户资料
user_profile, created = cls.objects.get_or_create(user=user)
return user_profile





43 changes: 41 additions & 2 deletions moiveRe/moiveReApp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .forms import RatingForm
from django.db.models import Avg
from django.shortcuts import get_object_or_404
from .models import Question, Rating
from .models import Question, Rating ,UserProfile,Userinterests
import random
from django.contrib.auth.decorators import login_required
#from recsystem.userCFrecommendation import usercf
Expand All @@ -13,6 +13,7 @@
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import math
from collections import Counter

class IndexView(generic.ListView):
template_name = "moiveReApp/index.html"
Expand Down Expand Up @@ -262,11 +263,43 @@ def generate_recommendations(target_user, item_similarity_matrix, user_item_matr
# 返回排序后的物品ID列表
return [item_id for item_id, _ in recommendations]
# ...

#兴趣标签更新
def update_uesrinterests(user_profile):
# 获取用户喜欢和点击的物品类别
liked_categories = [question.category for question in user_profile.liked_items.all()]
clicked_categories = [question.category for question in user_profile.click_items.all()]
all_categories = liked_categories + clicked_categories
# 计算频率
category_counter = Counter(all_categories)

# 根据一定的规则选择兴趣标签;这里我暂时就设置阈值
threshold = 4
interests = []
for category, count in category_counter.items():
# 这里可以根据你的规则选择兴趣标签,比如出现频率大于阈值的类别
if count >= threshold:
interests.append(category)

# 将选定的兴趣标签添加到用户的兴趣标签列表中
#user_profile.interests.clear() # 清除旧标签保持时效性
#print(interests)

for interest in interests:
user_interest, created = Userinterests.objects.get_or_create(name=interest)
user_profile.interests.add(user_interest)



def question_detail(request, question_id):
user_profile = UserProfile.get_user_profile(request.user)
question = get_object_or_404(Question, pk=question_id)
ratings = Rating.objects.filter(question=question)
avg_rating = ratings.aggregate(Avg('value'))['value__avg']
form = RatingForm()
user_profile.click_items.add(question)
question.clicks+=1
update_uesrinterests(user_profile)

if request.method == 'POST':
form = RatingForm(request.POST)
Expand Down Expand Up @@ -318,17 +351,23 @@ def random_questions(request):

@login_required
def like_question(request, question_id):
user_profile = UserProfile.get_user_profile(request.user)

question = get_object_or_404(Question, id=question_id)

if request.user in question.liked_by.all():
# 用户已经点过赞,取消点赞
question.liked_by.remove(request.user)
user_profile.liked_items.remove(question)
update_uesrinterests(user_profile)
if question.likes>0:
question.likes-=1
else:
# 用户还未点赞,添加点赞
question.liked_by.add(request.user)
user_profile.liked_items.add(question)
question.likes += 1
update_uesrinterests(user_profile)

question.save()

Expand Down Expand Up @@ -410,4 +449,4 @@ def bertcall(request):
recommended_movies = Question.objects.filter(id__in=recommendations[:8]) #只展示前ki个

# 在模板中渲染推荐结果
return render(request, 'moiveReApp/bertcall.html', {'recommended_movies': recommended_movies})
return render(request, 'moiveReApp/bertcall.html', {'recommended_movies': recommended_movies})
121 changes: 117 additions & 4 deletions moiveRe/recommendationrecall.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@


import torch
from transformers import DistilBertTokenizer, DistilBertModel
from sklearn.metrics.pairwise import cosine_similarity
import django
from django.conf import settings
import os
Expand All @@ -14,6 +16,16 @@
from sklearn.metrics.pairwise import cosine_similarity


from moiveReApp.models import UserProfile,Question
from django.contrib.auth.models import User


user = User.objects.get(username='gly233')
user_profile = UserProfile.get_user_profile(user)
question_list = Question.objects.all()




class itemcf():

Expand Down Expand Up @@ -110,20 +122,121 @@ def generate_recommendations(target_user, item_similarity_matrix, user_item_matr

# 根据感兴趣程度排序推荐列表
recommendations.sort(key=lambda x: x[1], reverse=True)
print(recommendations)


# 返回排序后的物品ID列表
return [item_id for item_id, _ in recommendations]
return recommendations

user_item_matrix, item_dict, user_dict = itemcf.build_user_item_matrix(question_list)
item_similarity_matrix = itemcf.calculate_user_similarity(user_item_matrix)
r1 = itemcf.generate_recommendations(user.id, item_similarity_matrix, user_item_matrix, user_dict, item_dict, k=30)[:10]


class hotitem():


def recall_hot_item(question_list,k):
sorted_question_list = sorted(question_list, key=lambda q: q.likes, reverse=True)
recommendations = [question.id for question in sorted_question_list]
return recommendations[:k]

r2 = hotitem.recall_hot_item(question_list,10)

class newitem():

def recall_new_item(question_list,k):
sorted_question_list = sorted(question_list, key=lambda q: q.pub_date, reverse=True)
recommendations = [question.id for question in sorted_question_list]
return recommendations[:k]

r3 = newitem.recall_new_item(question_list,10)


class U2TAG2I():



def compute_interest_score(user_profile, questions):
interest_scores = {}
user_interests = set(user_profile.interests.all())
user_interests_names = [interest.name for interest in user_interests]
#print(user_interests_names)
for question in questions:
if question.category in user_interests_names:
interest_scores[question.id] = 0.3
else:
interest_scores[question.id] = 0

return interest_scores

def compute_similarity(user_profile, questions):
tokenizer = DistilBertTokenizer.from_pretrained('distilbert-base-uncased')
model = DistilBertModel.from_pretrained('distilbert-base-uncased')
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

user_interests_str = ' '.join([interest.name for interest in user_profile.interests.all()])

question_details = [question.detail for question in questions]
num_questions = len(question_details)
question_ids = [question.id for question in questions]
question_score = []
#print(question_ids)
question_details.append(user_interests_str)
texts = question_details



inputs = tokenizer(texts, return_tensors='pt', padding=True, truncation=True)

# 将张量移动到GPU上
input_ids = inputs['input_ids'].to(device)
attention_mask = inputs['attention_mask'].to(device)
# 使用DistilBERT模型进行推理
with torch.no_grad():
outputs = model(input_ids=input_ids, attention_mask=attention_mask).last_hidden_state

# 将文本表示向量转移到CPU上
text_embeddings = outputs.mean(dim=1).cpu().numpy()

# 计算相似度
for i in range(num_questions):
similarity = cosine_similarity([text_embeddings[i]], [text_embeddings[-1]])[0][0]
question_score.append(similarity*0.7)

# 使用 zip() 函数合并两个列表成元组列表
combined = list(zip(question_ids, question_score))
# 将元组列表转换为字典
interest_score = dict(combined)

return interest_score

def generate_recommendations(score1,score2,k):
result_dict = {}
for key in score1:
if key in score2:
result_dict[key] = score1[key] + score2[key]

sorted_items = sorted(result_dict.items(), key=lambda x: x[1], reverse=True)
top_k = sorted_items[:k]
return top_k



a=U2TAG2I.compute_interest_score(user_profile,questions=question_list)
b=U2TAG2I.compute_similarity(user_profile,questions=question_list)

r4 = U2TAG2I.generate_recommendations(a,b,10)



print(r1)
print(r2)
print(r3)
print(r4)



return sorted_question_list[:k]



Expand Down
Loading

0 comments on commit a90aaa7

Please sign in to comment.