目录

第一章、绪论

1.1 研究背景与意义

1.2 国内外研究现状

1.3 论文主要研究内容

第二章、相关技术与理论基础

2.1 推荐算法概述

2.2 协同过滤关键步骤

2.3 系统开发技术栈

第三章、系统设计与实现

3.1 系统总体架构

3.2 数据模型设计

3.3 核心算法实现

3.4 后端API接口实现

3.5 前端Vue组件调用推荐API

第四章、系统测试与结果分析

4.1 实验环境与数据集

4.2 评估指标与结果

第五章、总结与展望

5.1 总结

5.2 展望

第一章、绪论

1.1 研究背景与意义

在信息时代,用户如何从海量电影中快速定位个人喜好,已成为提升流媒体平台用户粘性和满意度的核心问题。传统的搜索和分类浏览方式难以满足用户潜在的、个性化的观影需求。推荐系统作为一种信息过滤技术,能够通过分析用户的历史行为(如评分、点击),主动发现其兴趣偏好,并进行精准的内容推荐。研究表明,一个良好的推荐系统能将用户观看转化率提升20%-30%。因此,本研究旨在深入探索推荐算法,并构建一个实用的电影推荐系统,这不仅具有重要的理论价值,也为相关产业带来了明显的现实意义。

1.2 国内外研究现状

推荐系统的研究经历了从基于规则到基于内容,再到协同过滤及混合推荐的演变。国外研究起步较早,如Netflix举办的推荐算法大赛极大地推动了协同过滤和矩阵分解等技术的发展。国内研究同样成果显著,学者们在协同过滤的相似度计算、冷启动问题解决等方面提出了诸多改进方案。当前,随着深度学习技术的兴起,结合神经网络(如AutoRec)的推荐模型展现出更强的表示能力,成为新的研究热点。然而,协同过滤因其直观性和有效性,仍是许多实际应用系统的基石。

1.3 论文主要研究内容

本文核心工作包括:

系统分析与设计:​ 对电影推荐系统进行全面的需求分析,设计系统架构及数据库模型。

算法研究与实现:​ 深入研究并实现基于用户和基于物品的协同过滤算法,解决相似度计算、评分预测等关键问题。

系统开发与集成:​ 利用Django和Vue.js等主流技术栈,开发具有用户交互界面的完整Web应用系统。

系统测试与评估:​ 使用标准数据集对系统进行测试,并采用准确率、召回率、均方根误差(RMSE)等指标评估推荐效果。

第二章、相关技术与理论基础

2.1 推荐算法概述

推荐算法是本系统的核心。协同过滤(Collaborative Filtering, CF)是其中应用最广泛的算法之一,其核心思想是利用群体智慧,即“相似的用户喜欢相似的物品”(User-Based CF)或“相似的物品被相似的用户喜欢”(Item-Based CF)。

2.2 协同过滤关键步骤

数据表示:​ 构建用户-物品评分矩阵,矩阵中的每个元素代表用户对物品的评分。

相似度计算:​ 是协同过滤的关键步骤。常用的方法包括:

  1. 余弦相似度(Cosine Similarity):​ 通过计算两个向量夹角的余弦值来衡量其相似度,忽略向量的绝对大小,专注于方向上的差异。
  2. 皮尔逊相关系数(Pearson Correlation):​ 衡量两个向量之间的线性相关程度,能够修正用户评分尺度不一的问题。

评分预测与推荐生成:​ 找到最相似的K个用户或物品后,通过加权平均他们的评分,预测目标用户对未评分物品的喜好,并生成推荐列表。

2.3 系统开发技术栈

后端框架:Django。一个高级Python Web框架,提供了强大的ORM、模板引擎和自带的Admin管理后台,能快速构建稳健的后端服务。

前端框架:Vue.js。一套用于构建用户界面的渐进式JavaScript框架,易于上手,并能通过Vuex进行状态管理,通过Axios与后端API交互。

数据库:MySQL。一个成熟稳定的关系型数据库管理系统,用于存储用户、电影、评分等结构化数据。

第三章、系统设计与实现

3.1 系统总体架构

本系统采用前后端分离的架构,这使得前后端可以独立开发、测试和部署,提高了系统的可维护性和可扩展性。其核心工作流如下:

3.2 数据模型设计

核心数据表包括:

用户表 (auth_user):​ 存储用户基本信息,如用户名、密码(加密)。

电影表 (movie_movie):​ 存储电影信息,如标题、导演、演员、类型、上映年份、海报链接等。

评分表 (movie_rating):​ 存储用户对电影的评分记录,是推荐算法的数据基础。包含用户ID、电影ID、评分值、时间戳等字段。

3.3 核心算法实现

以下是使用Python和Pandas库实现协同过滤算法的核心代码。

a) 基于用户的协同过滤 (User-Based CF)

# recommender/cf_algorithms.py
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

class UserBasedCF:
    def __init__(self):
        self.user_item_matrix = None
        self.user_similarity = None

    def fit(self, ratings_df):
        """
        训练模型:构建用户-物品矩阵并计算用户相似度
        Args:
            ratings_df: DataFrame,包含'userId', 'movieId', 'rating'三列
        """
        # 创建用户-物品评分矩阵,未评分的用0填充
        self.user_item_matrix = ratings_df.pivot_table(
            index='userId', columns='movieId', values='rating'
        ).fillna(0)

        # 计算用户之间的余弦相似度
        self.user_similarity = cosine_similarity(self.user_item_matrix)
        # 将相似度矩阵转换为DataFrame,索引和列名为用户ID
        self.user_similarity = pd.DataFrame(
            self.user_similarity,
            index=self.user_item_matrix.index,
            columns=self.user_item_matrix.index
        )

    def recommend(self, target_user_id, top_n=10):
        """
        为目标用户生成推荐列表
        Args:
            target_user_id: 目标用户ID
            top_n: 推荐电影的数量
        Returns:
            recommended_movies: 推荐的电影ID列表
        """
        if target_user_id not in self.user_item_matrix.index:
            return []  # 处理新用户问题(冷启动)

        # 获取目标用户的评分向量
        target_user_ratings = self.user_item_matrix.loc[target_user_id]

        # 找到与目标用户最相似的K个用户(排除自己)
        similar_users = self.user_similarity[target_user_id].sort_values(ascending=False).iloc[1:11]  # 取前10个相似用户

        # 初始化加权评分和
        weighted_scores = pd.Series(0, index=self.user_item_matrix.columns)
        # 初始化相似度总和,用于归一化
        total_similarity = pd.Series(0, index=self.user_item_matrix.columns)

        for sim_user_id, similarity in similar_users.items():
            # 获取相似用户的评分向量
            sim_user_ratings = self.user_item_matrix.loc[sim_user_id]
            # 只考虑目标用户未评分但相似用户已评分的电影
            unwatched_mask = target_user_ratings == 0
            # 计算加权评分 (相似度 * 评分)
            weighted_scores[unwatched_mask] += similarity * sim_user_ratings[unwatched_mask]
            # 累计相似度
            total_similarity[unwatched_mask] += np.abs(similarity)

        # 避免除以零,计算预测评分
        prediction_scores = weighted_scores / (total_similarity + 1e-8)  # 加一个极小值防止除零
        # 剔除已评分的电影
        prediction_scores = prediction_scores[unwatched_mask]
        # 按预测评分降序排列,取前top_n个作为推荐
        top_recommendations = prediction_scores.sort_values(ascending=False).head(top_n).index.tolist()

        return top_recommendations

代码说明:此代码实现了User-Based CF的核心逻辑。fit方法根据评分数据构建用户-物品矩阵并计算用户相似度。recommend方法则为指定用户生成推荐:它找到相似用户,聚合他们的评分(用相似度加权),并预测目标用户对未观看电影的评分,最后返回评分最高的若干电影。

b) 基于物品的协同过滤 (Item-Based CF)

# recommender/cf_algorithms.py (续)
class ItemBasedCF:
    def __init__(self):
        self.item_similarity = None
        self.user_item_matrix = None

    def fit(self, ratings_df):
        """
        训练模型:构建物品-用户矩阵并计算物品相似度
        """
        # 创建物品-用户评分矩阵 (用户-物品矩阵的转置)
        item_user_matrix = ratings_df.pivot_table(
            index='movieId', columns='userId', values='rating'
        ).fillna(0)

        self.user_item_matrix = item_user_matrix.T # 保存为用户-物品矩阵格式,方便后续使用

        # 计算物品之间的余弦相似度
        self.item_similarity = cosine_similarity(item_user_matrix)
        self.item_similarity = pd.DataFrame(
            self.item_similarity,
            index=item_user_matrix.index,
            columns=item_user_matrix.index
        )

    def recommend(self, target_user_id, top_n=10):
        """
        基于物品的协同过滤推荐
        """
        if target_user_id not in self.user_item_matrix.index:
            return []

        target_user_ratings = self.user_item_matrix.loc[target_user_id]
        # 获取用户已经评分的电影
        rated_movies = target_user_ratings[target_user_ratings > 0].index

        prediction_scores = pd.Series(0, index=self.user_item_matrix.columns)

        for movie_id in rated_movies:
            user_rating = target_user_ratings[movie_id]
            # 获取当前已评分电影的相似电影
            similar_movies = self.item_similarity[movie_id].sort_values(ascending=False).iloc[1:21] # 取前20个相似电影
            # 对于每个相似电影,累加 (相似度 * 用户对已评分电影的评分)
            for sim_movie_id, similarity in similar_movies.items():
                if target_user_ratings[sim_movie_id] == 0: # 只考虑用户未评分的电影
                    prediction_scores[sim_movie_id] += similarity * user_rating

        # 剔除用户已经评分的电影
        prediction_scores = prediction_scores.drop(rated_movies, errors='ignore')
        # 按预测评分降序排列,取前top_n个
        top_recommendations = prediction_scores.sort_values(ascending=False).head(top_n).index.tolist()

        return top_recommendations

代码说明:Item-Based CF的核心是计算物品间的相似度。fit方法构建物品-用户矩阵并计算物品相似度。recommend方法则根据目标用户的历史评分记录,找到与其喜欢物品相似的、且用户未评分的物品,进行加权推荐。

3.4 后端API接口实现

使用Django REST Framework创建推荐API。

# api/views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.http import JsonResponse
from .models import Rating, Movie
from .recommender.cf_algorithms import UserBasedCF, ItemBasedCF
import pandas as pd

@api_view(['GET'])
def get_recommendations(request, user_id):
    """
    获取为用户推荐的电影列表
    """
    # 从数据库获取评分数据
    ratings_queryset = Rating.objects.all().values('userId', 'movieId', 'rating')
    ratings_df = pd.DataFrame.from_records(ratings_queryset)

    # 初始化推荐器并训练模型 (可根据需求选择User-Based或Item-Based)
    # recommender = UserBasedCF()
    recommender = ItemBasedCF()
    recommender.fit(ratings_df)

    # 生成推荐
    recommended_movie_ids = recommender.recommend(target_user_id=user_id, top_n=10)

    # 根据推荐的电影ID获取详细的电影信息
    recommended_movies = Movie.objects.filter(movieId__in=recommended_movie_ids).values('movieId', 'title', 'genres', 'poster')
    recommended_movies_list = list(recommended_movies)

    return JsonResponse({'recommended_movies': recommended_movies_list})
3.5 前端Vue组件调用推荐API
<!-- components/RecommendationList.vue -->
<template>
  <div class="recommendation">
    <h2>为您推荐的电影</h2>
    <div v-if="loading">加载中...</div>
    <div v-else class="movie-list">
      <div v-for="movie in movies" :key="movie.movieId" class="movie-card">
        <img :src="movie.poster" :alt="movie.title" class="movie-poster">
        <div class="movie-info">
          <h3>{{ movie.title }}</h3>
          <p>{{ movie.genres }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  name: 'RecommendationList',
  data() {
    return {
      movies: [],
      loading: true,
      currentUserId: 123 // 应从用户状态管理(如Vuex)或登录信息中获取实际用户ID
    };
  },
  mounted() {
    this.fetchRecommendations();
  },
  methods: {
    async fetchRecommendations() {
      try {
        const response = await axios.get(`/api/recommendations/${this.currentUserId}`);
        this.movies = response.data.recommended_movies;
      } catch (error) {
        console.error('获取推荐失败:', error);
      } finally {
        this.loading = false;
      }
    }
  }
};
</script>

代码说明:此前端Vue组件在页面加载时(mounted钩子)通过Axios调用后端的推荐API。获取到推荐的电影列表后,将其渲染在页面上。这体现了前后端分离架构的协作方式。

第四章、系统测试与结果分析

4.1 实验环境与数据集

实验环境:​ Python 3.8, Django 4.2, Vue 3.x, MySQL 8.0。

数据集:​ 使用MovieLens ml-latest-small数据集,包含约10万条评分数据。

评估方法:​ 采用留出法(Holdout),将数据集按70%/30%的比例划分为训练集和测试集。

4.2 评估指标与结果

为了科学评估推荐效果,需要使用多种指标。下表展示了在测试集上对两种协同过滤算法的评估结果:

评估指标​

基于用户的CF​

基于物品的CF​

说明​

准确率 (Precision@10)​

0.35

0.40

推荐列表中用户真正喜欢的电影比例。Item-Based CF略优。

召回率 (Recall@10)​

0.15

0.18

系统找出的用户喜欢电影占所有用户喜欢电影的比例。

覆盖率 (Coverage)​

0.60

0.75

推荐系统能够推荐出的电影占总电影目录的比例。Item-Based CF通常有更高覆盖率。

RMSE​

0.85

0.82

预测评分与真实评分之间的误差,值越小越好。

结果分析:基于物品的协同过滤(Item-Based CF)在本实验环境下综合表现稍好,尤其是在准确率和覆盖率上。这可能是因为电影间的相似性比用户间的相似性更稳定。

第五章、总结与展望

5.1 总结

本研究成功设计并实现了一个基于协同过滤算法的电影推荐系统。其主要贡献在于:

算法实现与对比:​ 完整实现了User-Based和Item-Based协同过滤算法,并进行了对比实验。

系统集成:​ 将推荐算法与成熟的Web开发技术(Django, Vue.js)相结合,构建了功能完整、用户友好的应用系统。

实践价值:​ 为理解推荐系统原理、进行算法实践和二次开发提供了一个良好的基础平台。

5.2 展望

系统仍有优化和扩展空间:

算法优化:​ 引入矩阵分解(如SVD++)​ 或深度学习模型(如神经协同过滤NCF)来处理稀疏性和捕捉更复杂的用户-物品交互关系。

解决冷启动:​ 探索融合基于内容的推荐(利用电影剧情、演员等特征)或利用社交信息来缓解新用户和新电影的冷启动问题。

引入实时性:​ 研究如何将用户的最新行为(如最近点击)快速融入推荐模型,实现实时或近实时推荐。

多样化评估:​ 除了离线指标,未来可进行A/B测试,在线评估推荐系统对用户点击率、留存时长等业务指标的真实影响。


开源代码

链接:https://pan.baidu.com/s/1BQnc_JPpc6eOcXByks98oA?pwd=j3v7 提取码:j3v7

更多推荐