用Python+Surprise库5分钟搭建你的第一个电影推荐系统

推荐系统早已渗透进我们数字生活的每个角落——从电商平台的"猜你喜欢"到视频网站的"推荐观看",背后都藏着精妙的算法逻辑。但你是否想过,这些看似神秘的推荐功能,其实用不到50行Python代码就能实现?本文将带你用Surprise库快速搭建一个基于协同过滤的电影推荐系统,无需复杂数学推导,直接体验算法落地的快感。

1. 环境准备与数据加载

推荐系统的核心是数据。我们选用经典的MovieLens数据集,这个包含用户对电影评分的数据集堪称推荐算法界的"MNIST"。首先确保你的Python环境已安装以下库:

pip install scikit-surprise pandas numpy

Surprise(Simple Python Recommendation System Engine)是专为构建和分析推荐系统设计的Python库,它封装了常见的协同过滤算法,让我们能专注于业务逻辑而非数学实现。加载数据只需几行代码:

from surprise import Dataset
from surprise import Reader

# 定义数据格式
reader = Reader(line_format='user item rating timestamp', sep='\t')
# 加载内置的MovieLens 100K数据集
data = Dataset.load_builtin('ml-100k')

如果想使用自定义数据集(比如你的业务数据),可以这样处理:

import pandas as pd
from surprise import Dataset

ratings = pd.read_csv('your_ratings.csv')  
data = Dataset.load_from_df(ratings[['user_id', 'item_id', 'rating']], 
                           reader=Reader(rating_scale=(1, 5)))

数据加载后,Surprise会自动将其转换为适合算法处理的格式。MovieLens 100K数据集包含:

指标 数量
用户数 943
电影数 1682
评分记录 100,000
评分范围 1-5星

2. 算法选择与模型训练

Surprise提供了多种推荐算法,我们主要比较三种经典协同过滤实现:

  1. 基于用户的协同过滤(User-based KNN):找出相似用户喜欢的物品
  2. 基于物品的协同过滤(Item-based KNN):找出相似物品
  3. 矩阵分解(SVD):通过降维发现潜在特征

以下是三种算法的实现对比:

from surprise import KNNWithMeans, SVD
from surprise.model_selection import cross_validate

# 用户协同过滤
user_cf = KNNWithMeans(k=50, sim_options={'user_based': True})
# 物品协同过滤
item_cf = KNNWithMeans(k=50, sim_options={'user_based': False})
# 矩阵分解
svd = SVD()

# 交叉验证比较
for algo in [user_cf, item_cf, svd]:
    results = cross_validate(algo, data, measures=['RMSE'], cv=5, verbose=True)

典型输出结果对比:

算法 RMSE均值 训练时间
User-based 0.94 2.1s
Item-based 0.98 1.8s
SVD 0.93 3.4s

可以看到SVD虽然稍慢但准确率最高,适合我们的场景。选定算法后,完整训练流程如下:

from surprise import SVD
from surprise import accuracy
from surprise.model_selection import train_test_split

# 划分训练测试集
trainset, testset = train_test_split(data, test_size=0.25)

# 初始化并训练模型
algo = SVD(n_factors=100, n_epochs=20, lr_all=0.005, reg_all=0.02)
algo.fit(trainset)

# 测试集评估
predictions = algo.test(testset)
accuracy.rmse(predictions)

关键参数说明:

  • n_factors: 潜在特征维度(通常50-200)
  • n_epochs: 训练迭代次数
  • lr_all: 学习率
  • reg_all: 正则化系数

3. 推荐生成与效果优化

模型训练完成后,实际推荐只需调用predict方法:

# 为用户17推荐电影
user_id = '17'
items = ['302', '287', '292']  # 候选电影ID列表

for item_id in items:
    pred = algo.predict(user_id, item_id)
    print(f"电影{item_id}的预测评分: {pred.est:.2f}")

要生成Top-N推荐,可以这样实现:

def get_top_n(predictions, user_id, n=10):
    top_n = {}
    for uid, iid, true_r, est, _ in predictions:
        if uid == user_id:
            top_n[iid] = est
    
    return sorted(top_n.items(), key=lambda x: x[1], reverse=True)[:n]

# 为所有用户生成推荐
testset = trainset.build_anti_testset()
predictions = algo.test(testset)

# 获取用户196的Top5推荐
user_196_top5 = get_top_n(predictions, '196', 5)
print("用户196的Top5推荐电影:", user_196_top5)

效果优化技巧

  1. 参数调优:使用GridSearchCV自动搜索最优参数

    from surprise.model_selection import GridSearchCV
    
    param_grid = {'n_factors': [50, 100, 150],
                  'n_epochs': [20, 30],
                  'lr_all': [0.002, 0.005],
                  'reg_all': [0.02, 0.1]}
    gs = GridSearchCV(SVD, param_grid, measures=['rmse'], cv=3)
    gs.fit(data)
    print(gs.best_params)
    
  2. 混合推荐:结合基于内容的过滤

    # 假设我们有电影特征矩阵
    from sklearn.metrics.pairwise import cosine_similarity
    
    def content_filtering(movie_id, k=5):
        # 返回与目标电影最相似的k部电影
        similarities = cosine_similarity(feature_matrix[movie_id].reshape(1,-1), 
                                       feature_matrix)
        return np.argsort(similarities[0])[-k-1:-1][::-1]
    
  3. 冷启动处理:对于新用户/新物品,可以采用:

    • 热门推荐
    • 基于内容的推荐
    • 混合策略

4. 部署与扩展思路

虽然我们使用小数据集演示,但实际应用中需要考虑:

性能优化方案

# 使用更高效的算法实现
from surprise import SVDpp, NMF

# 增量学习
algo = SVD()
algo.fit(trainset)
new_ratings = [('196', '302', 4), ('196', '287', 3)] 
algo.update(new_ratings)

部署架构示例

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  客户端APP   │───▶│ API服务层   │───▶│ 推荐引擎    │
└─────────────┘    └─────────────┘    └─────────────┘
                         │                   ▲
                         ▼                   │
                    ┌─────────────┐    ┌─────────────┐
                    │ 用户行为收集 │    │ 模型训练服务│
                    └─────────────┘    └─────────────┘

进阶方向

  1. 实时推荐:结合流处理框架(如Kafka+Spark)
  2. 深度学习:使用TensorFlow Recommenders
  3. 可解释性:添加推荐理由生成
  4. 多目标优化:平衡准确性、多样性、新颖性
# 简单多样性增强实现
import random

def diverse_recommend(predictions, user_id, n=10, diversity=0.5):
    top_items = get_top_n(predictions, user_id, n*2)
    random.shuffle(top_items)
    return top_items[:int(n*(1-diversity))] + random.sample(top_items, int(n*diversity))

从零搭建推荐系统不再是大厂的专利。借助Surprise这样的工具库,开发者可以快速验证想法,将推荐能力集成到自己的应用中。虽然工业级系统需要考虑更多复杂因素,但核心逻辑与我们今天实现的并无二致。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐