基于协同过滤的电影推荐系统

推荐系统已经成为当今互联网平台不可或缺的一部分,尤其是在电影、音乐和电子商务等领域。本文将带您深入探讨如何利用协同过滤算法,构建一个功能齐全的电影推荐系统。我们将结合Python、Django框架以及协同过滤算法,逐步实现这一目标。

完整项目:基于协同过滤的电影推荐系统

目录

  1. 项目背景
  2. 环境配置与依赖
  3. 数据导入与处理
  4. 协同过滤算法实现
  5. 前端页面展示
  6. 项目优化与总结

1. 项目背景

在当今的互联网环境中,推荐系统能够有效提高用户体验,帮助用户发现自己感兴趣的内容。本项目的主要目标是通过协同过滤技术,为用户推荐他们可能感兴趣的电影。我们将通过以下几个步骤完成该系统的搭建:

  • 从CSV文件中导入电影和用户数据
  • 构建用户和电影的关系模型
  • 通过协同过滤算法实现电影推荐
  • 在前端页面展示推荐结果

2. 环境配置与依赖

在开始之前,我们需要确保开发环境配置正确,并安装必要的依赖项。我们使用的是Django框架,因此需要在项目目录下配置settings.py文件,并安装以下依赖:

pip install django
pip install pandas

 

3. 数据导入与处理

3.1 导入电影类型数据

我们首先从一个预定义的文本文件中导入电影类型数据。代码如下所示:

def get_genre():
    '''导入所有电影类型'''
    path = os.path.join(BASE, 'static/movie/info/genre.txt')
    with open(path) as fb:
        for line in fb:
            Genre.objects.create(name=line.strip())

该函数从指定路径读取电影类型,并将其存储到数据库的Genre表中。

3.2 导入电影信息

接下来,我们从CSV文件中导入电影的详细信息,并关联它们的类型。这部分代码的实现如下:

def get_movie_info():
    '''导入所有电影信息,并设置它们的类型'''
    path = os.path.join(BASE, 'static/movie/info/info.csv')
    with open(path) as fb:
        reader = csv.reader(fb)
        title = next(reader)
        title_dct = dict(zip(title, range(len(title))))
        
        for i, line in enumerate(reader):
            movie = Movie.objects.create(
                name=line[title_dct['name']],
                imdb_id=line[title_dct['id']],
                time=line[title_dct['time']],
                release_time=line[title_dct['release_time']],
                intro=line[title_dct['intro']],
                director=line[title_dct['directors']],
                writers=line[title_dct['writers']],
                actors=line[title_dct['starts']]
            )
            movie.save()
            for genre in line[title_dct['genre']].split('|'):
                genre_obj = Genre.objects.filter(name=genre).first()
                movie.genre.add(genre_obj)
            if i % 1000 == 0:
                print(i)

此函数读取电影信息并逐条保存到数据库中。它还处理了电影和类型之间的多对多关系。

3.3 导入用户评分数据

为了实现推荐系统,我们还需要导入用户的评分数据。以下是对应的实现:

def get_user_and_rating():
    '''获取用户信息并设置对电影的评分'''
    path = os.path.join(BASE, 'static/movie/info/ratings.csv')
    with open(path) as fb:
        reader = csv.reader(fb)
        title = next(reader)
        title_dct = dict(zip(title, range(len(title))))
        
        user_id_dct = {}
        for line in reader:
            user_id = line[title_dct['userId']]
            imdb_id = line[title_dct['movieId']]
            rating = line[title_dct['rating']]
            user_id_dct.setdefault(user_id, {})
            user_id_dct[user_id][imdb_id] = rating
            
        for user_id, ratings in user_id_dct.items():
            user = User.objects.create(name=user_id, password=user_id, email=f'{user_id}@1.com')
            user.save()
            for imdb_id, rating in ratings.items():
                movie = Movie.objects.get(imdb_id=imdb_id)
                relation = Movie_rating(user=user, movie=movie, score=rating, comment='')
                relation.save()
            print(f'{user_id} process success')

该函数从CSV文件中读取用户评分,并保存到Movie_rating表中,形成用户和电影的关联。

4. 协同过滤算法实现

在处理完数据导入之后,我们开始实现协同过滤算法,以生成电影推荐。以下是算法的核心部分:

class RecommendMovieView(ListView):
    def __init__(self):
        super().__init__()
        self.K = 20  # 最相似的20个用户
        self.N = 10  # 推荐10部电影
        self.cur_user_movie_qs = None

    def get_user_sim(self):
        '''计算用户相似度'''
        user_sim_dct = {}
        cur_user_id = self.request.session['user_id']
        cur_user = User.objects.get(pk=cur_user_id)
        other_users = User.objects.exclude(pk=cur_user_id)
        self.cur_user_movie_qs = Movie.objects.filter(user=cur_user)
        
        for user in other_users:
            user_sim_dct[user.id] = len(Movie.objects.filter(user=user) & self.cur_user_movie_qs)
        return sorted(user_sim_dct.items(), key=lambda x: -x[1])[:self.K]

    def get_recommend_movie(self, user_lst):
        '''获取推荐的电影列表'''
        movie_val_dct = {}
        for user, _ in user_lst:
            movie_set = Movie.objects.filter(user=user).exclude(id__in=self.cur_user_movie_qs).annotate(
                score=Max('movie_rating__score'))
            for movie in movie_set:
                movie_val_dct.setdefault(movie, 0)
                movie_val_dct[movie] += movie.score
        return sorted(movie_val_dct.items(), key=lambda x: -x[1])[:self.N]

    def get_queryset(self):
        user_lst = self.get_user_sim()
        movie_lst = self.get_recommend_movie(user_lst)
        return [movie for movie, _ in movie_lst]

这个类实现了基于用户相似度的电影推荐。它通过计算当前用户与其他用户的相似度,生成一个推荐电影的列表。

5. 前端页面展示

有了推荐算法之后,我们需要在前端展示推荐结果。我们使用Django的ListView类来展示电影列表。以下是一个简单的例子:

class IndexView(ListView):
    model = Movie
    template_name = 'movie/index.html'
    paginate_by = 15
    context_object_name = 'movies'
    ordering = 'imdb_id'
    page_kwarg = 'p'

    def get_queryset(self):
        return Movie.objects.filter(imdb_id__lte=1000)

通过这个视图类,我们可以在主页上展示前1000部电影,并支持分页功能。

6. 项目优化与总结

在完成上述步骤后,我们的电影推荐系统已经基本成型。但为了提升性能和用户体验,我们还可以做一些优化,例如:

  • 缓存用户相似度和推荐结果,减少计算开销
  • 使用异步任务队列(如Celery)来处理耗时的推荐计算
  • 提供更加个性化的推荐,结合用户行为数据

本项目展示了如何利用协同过滤技术构建一个基本的电影推荐系统。通过不断的迭代和优化,我们可以逐步提升系统的推荐准确性和用户体验。如果你对推荐系统感兴趣,欢迎继续探索更为复杂的算法和实现。

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值