实验基本信息
实验项目:基于 MovieLens-100K 数据集的推荐算法设计与实现
实验时间:2025 年 12 月
实验环境:python 3.12.9
一、实验目标
1.1 核心目标
本次实验旨在通过 MovieLens-100K 数据集深入研究推荐算法的理论与实践,掌握推荐系统的核心技术,并培养算法实现和实验分析能力。
1.2 具体目标
- 算法原理理解:深入理解协同过滤(User-CF、Item-CF)、基于邻域的评分预测及矩阵分解等算法的思想与数学逻辑
- 数据处理能力:掌握 MovieLens-100K 数据集的结构与预处理方法
- 算法实现能力:使用 实现推荐算法,包括 User-CF、Item-CF、SVD、LFM 等
- 评估分析能力:通过 MAE、RMSE 等指标对比不同算法的推荐效果
二、实验环境
2.1 硬件环境
- 处理器:Intel Core i5 8 核处理器
- 内存:32GB DDR4 3200MHz
- 存储:1TB SSD
- 操作系统:Ubuntu 22.04.3 LTS
2.2 软件环境
- 版本:3.12.9
- 核心库版本:
- numpy==1.26.4
- pandas==2.2.3
- scikit-learn==1.5.2
- matplotlib==3.9.2
- scipy==1.13.1
三、算法原理
3.1 协同过滤算法
3.1.1 基于用户的协同过滤(User-CF)
核心思想:如果两个用户在过去的评分行为上相似,那么他们对未评分的物品的评分也可能会相似。
算法步骤:
- 计算用户之间的相似度矩阵(余弦相似度)
- 找到与目标用户最相似的前 K 个用户
- 基于相似用户的评分加权预测目标用户对未评分物品的评分
- 按预测评分降序排列,推荐评分最高的 N 个物品
3.1.2 基于物品的协同过滤(Item-CF)
核心思想:如果两个物品在过去的评分行为上相似,那么用户对其中一个物品的评分也可能会对另一个物品的评分有相似的偏好。
算法步骤:
- 计算物品之间的相似度矩阵(余弦相似度)
- 找到用户喜欢的电影(评分≥3 分)
- 对每个喜欢的电影,找到最相似的前 K 个电影
- 基于相似度和用户评分加权预测评分
- 按预测评分降序排列,推荐评分最高的 N 个物品
3.2 矩阵分解算法
3.2.1 奇异值分解(SVD)
核心思想:将用户 - 物品评分矩阵分解为用户特征矩阵和物品特征矩阵的乘积,通过低维潜在因子来捕捉用户和物品之间的复杂关系。
算法步骤:
- 使用截断 SVD 对评分矩阵进行降维分解
- 通过用户特征向量和物品特征向量的点积预测评分
- 按预测评分降序排列,推荐评分最高的 N 个物品
3.2.2 隐语义模型(LFM)
核心思想:假设用户对物品的评分由用户和物品在潜在因子空间中的交互决定,通过机器学习方法学习用户和物品的潜在特征。
算法步骤:
- 初始化用户特征矩阵、物品特征矩阵和偏置项
- 使用随机梯度下降(SGD)优化目标函数
- 加入早停机制防止过拟合
- 通过学习到的参数预测评分并推荐物品
四、实验步骤
4.1 数据准备阶段
4.1.1 数据集下载与加载
首先需要下载 MovieLens-100K 数据集:
bash
bash
# 创建数据目录
mkdir -p ml-100k
cd ml-100k
# 下载数据集
wget https://files.grouplens.org/datasets/movielens/ml-100k/u.data
wget https://files.grouplens.org/datasets/movielens/ml-100k/u.item
wget https://files.grouplens.org/datasets/movielens/ml-100k/u.user
加载数据集:
python
import pandas as pd
# 加载评分数据
ratings_df = pd.read_csv('ml-100k/u.data', sep='\t',
names=['user_id', 'item_id', 'rating', 'timestamp'],
encoding='latin-1')
# 加载电影数据
movies_df = pd.read_csv('ml-100k/u.item', sep='|',
names=['item_id', 'title', 'release_date', 'video_release_date',
'IMDb_URL', 'unknown', 'Action', 'Adventure', 'Animation',
'Children', 'Comedy', 'Crime', 'Documentary', 'Drama',
'Fantasy', 'Film-Noir', 'Horror', 'Musical', 'Mystery',
'Romance', 'Sci-Fi', 'Thriller', 'War', 'Western'],
encoding='latin-1', usecols=['item_id', 'title'])
# 加载用户数据
users_df = pd.read_csv('ml-100k/u.user', sep='|',
names=['user_id', 'age', 'gender', 'occupation', 'zip_code'],
encoding='latin-1')
4.1.2 数据探索与预处理
python
# 数据探索:查看数据集基本属性
print("数据集基本信息:")
print(f"用户数量:{users_df['user_id'].nunique()}")
print(f"电影数量:{movies_df['item_id'].nunique()}")
print(f"评分记录:{len(ratings_df)}")
print(f"评分范围:{ratings_df['rating'].min()} - {ratings_df['rating'].max()}")
print(f"数据稀疏度:{len(ratings_df) / (943 * 1682):.4f}") # 943和1682为数据集总用户数和电影数
# 创建用户-电影评分矩阵
user_movie_matrix = ratings_df.pivot_table(
index='user_id',
columns='item_id',
values='rating',
fill_value=0 # 缺失评分填充为0
)
# 确保矩阵包含所有用户和电影(用户ID 1-943,电影ID 1-1682)
all_users = range(1, 944)
all_movies = range(1, 1683)
user_movie_matrix = user_movie_matrix.reindex(
index=all_users,
columns=all_movies,
fill_value=0
)
print(f"\n评分矩阵维度:{user_movie_matrix.shape}")
4.2 算法实现阶段
4.2.1 协同过滤算法实现
User-CF 实现:
python
from sklearn.metrics.pairwise import cosine_similarity
# 计算用户相似度矩阵(余弦相似度)
def calculate_user_similarity(matrix):
"""计算用户之间的余弦相似度"""
similarity = cosine_similarity(matrix)
similarity_df = pd.DataFrame(
similarity,
index=matrix.index,
columns=matrix.index
)
return similarity_df
# User-CF推荐函数
def user_based_recommendation(user_id, user_movie_matrix, user_similarity,
movies_df, top_n=5, k_neighbors=20):
"""基于用户的协同过滤推荐"""
# 获取目标用户已评分的电影
user_ratings = ratings_df[ratings_df['user_id'] == user_id]
rated_items = set(user_ratings['item_id'].values)
# 获取所有电影ID
all_items = set(user_movie_matrix.columns)
candidate_items = all_items - rated_items
# 获取相似用户
similar_users = user_similarity.loc[user_id].sort_values(ascending=False)
similar_users = similar_users.drop(user_id).head(k_neighbors)
# 计算预测评分
predictions = {}
for item_id in candidate_items:
item_ratings = ratings_df[ratings_df['item_id'] == item_id]
weighted_sum = 0.0
similarity_sum = 0.0
for neighbor_id, similarity in similar_users.items():
neighbor_rating = item_ratings[item_ratings['user_id'] == neighbor_id]
if not neighbor_rating.empty:
rating = neighbor_rating['rating'].iloc[0]
weighted_sum += similarity * rating
similarity_sum += abs(similarity)
if similarity_sum > 0:
predicted_rating = weighted_sum / similarity_sum
predictions[item_id] = predicted_rating
# 排序并返回结果
sorted_predictions = sorted(predictions.items(), key=lambda x: x[1], reverse=True)
top_predictions = sorted_predictions[:top_n]
# 添加电影标题
recommendations = []
for item_id, predicted_rating in top_predictions:
title = movies_df[movies_df['item_id'] == item_id]['title'].iloc[0]
recommendations.append({
'item_id': item_id,
'title': title,
'predicted_rating': round(predicted_rating, 2)
})
return recommendations
Item-CF 实现:
python
# 计算物品相似度矩阵
def calculate_item_similarity(matrix):
"""计算物品之间的余弦相似度"""
item_matrix = matrix.T
similarity = cosine_similarity(item_matrix)
similarity_df = pd.DataFrame(
similarity,
index=item_matrix.index,
columns=item_matrix.index
)
return similarity_df
# Item-CF推荐函数
def item_based_recommendation(user_id, user_movie_matrix, item_similarity,
movies_df, top_n=5, k_similar_items=20):
"""基于物品的协同过滤推荐"""
# 获取用户喜欢的电影(评分≥3分)
user_ratings = ratings_df[ratings_df['user_id'] == user_id]
liked_items = user_ratings[user_ratings['rating'] >= 3]
# 获取已评分的电影
rated_items = set(user_ratings['item_id'].values)
all_items = set(user_movie_matrix.columns)
candidate_items = all_items - rated_items
# 计算预测评分
predictions = {}
for item_id in candidate_items:
weighted_sum = 0.0
similarity_sum = 0.0
for _, liked_item in liked_items.iterrows():
liked_item_id = liked_item['item_id']
user_rating = liked_item['rating']
if item_id in item_similarity.index:
similarity = item_similarity.loc[liked_item_id, item_id]
weighted_sum += similarity * user_rating
similarity_sum += abs(similarity)
if similarity_sum > 0:
predicted_rating = weighted_sum / similarity_sum
predictions[item_id] = predicted_rating
# 排序并返回结果
sorted_predictions = sorted(predictions.items(), key=lambda x: x[1], reverse=True)
top_predictions = sorted_predictions[:top_n]
# 添加电影标题
recommendations = []
for item_id, predicted_rating in top_predictions:
title = movies_df[movies_df['item_id'] == item_id]['title'].iloc[0]
recommendations.append({
'item_id': item_id,
'title': title,
'predicted_rating': round(predicted_rating, 2)
})
return recommendations
4.2.2 矩阵分解算法实现
SVD 实现:
python
import numpy as np
from sklearn.decomposition import TruncatedSVD
# SVD分解与推荐
def svd_recommendation(user_id, user_movie_matrix, movies_df,
n_components=50, top_n=5):
"""基于SVD的推荐"""
# SVD分解
svd = TruncatedSVD(n_components=n_components, random_state=42)
user_features = svd.fit_transform(user_movie_matrix)
item_features = svd.components_
# 获取目标用户已评分的电影
user_ratings = ratings_df[ratings_df['user_id'] == user_id]
rated_items = set(user_ratings['item_id'].values)
# 获取所有电影ID
all_items = set(user_movie_matrix.columns)
candidate_items = all_items - rated_items
# 计算预测评分
user_idx = user_id - 1
predictions = {}
for item_id in candidate_items:
item_idx = item_id - 1
if item_idx < item_features.shape[1]:
predicted_rating = np.dot(user_features[user_idx], item_features[:, item_idx])
predicted_rating = max(1.0, min(5.0, predicted_rating))
predictions[item_id] = predicted_rating
# 排序并返回结果
sorted_predictions = sorted(predictions.items(), key=lambda x: x[1], reverse=True)
top_predictions = sorted_predictions[:top_n]
# 添加电影标题
recommendations = []
for item_id, predicted_rating in top_predictions:
title = movies_df[movies_df['item_id'] == item_id]['title'].iloc[0]
recommendations.append({
'item_id': item_id,
'title': title,
'predicted_rating': round(predicted_rating, 2)
})
return recommendations, svd
LFM 实现:
python
from sklearn.metrics import mean_squared_error
class LatentFactorModel:
def __init__(self, n_factors=50, lambda_reg=0.01, alpha=0.005,
n_epochs=50, early_stopping=True, patience=5):
self.n_factors = n_factors
self.lambda_reg = lambda_reg
self.alpha = alpha
self.n_epochs = n_epochs
self.early_stopping = early_stopping
self.patience = patience
self.user_features = None
self.item_features = None
self.user_bias = None
self.item_bias = None
self.global_bias = None
def fit(self, matrix):
"""训练LFM模型"""
n_users, n_items = matrix.shape
self.global_bias = np.mean(matrix[matrix > 0])
# 初始化参数
self.user_features = np.random.normal(scale=1./self.n_factors,
size=(n_users, self.n_factors))
self.item_features = np.random.normal(scale=1./self.n_factors,
size=(n_items, self.n_factors))
self.user_bias = np.zeros(n_users)
self.item_bias = np.zeros(n_items)
# 收集非零评分的位置
non_zero_indices = np.where(matrix > 0)
non_zero_users = non_zero_indices[0]
non_zero_items = non_zero_indices[1]
non_zero_ratings = matrix[non_zero_indices]
best_rmse = float('inf')
best_epoch = 0
for epoch in range(self.n_epochs):
# 随机打乱数据
permutation = np.random.permutation(len(non_zero_users))
users = non_zero_users[permutation]
items = non_zero_items[permutation]
ratings = non_zero_ratings[permutation]
# 批量更新
for u, i, r in zip(users, items, ratings):
prediction = self.global_bias + self.user_bias[u] + self.item_bias[i] + \
np.dot(self.user_features[u], self.item_features[i])
error = r - prediction
# 更新偏置项
self.user_bias[u] += self.alpha * (error - self.lambda_reg * self.user_bias[u])
self.item_bias[i] += self.alpha * (error - self.lambda_reg * self.item_bias[i])
# 更新特征矩阵
self.user_features[u] += self.alpha * (error * self.item_features[i] -
self.lambda_reg * self.user_features[u])
self.item_features[i] += self.alpha * (error * self.user_features[u] -
self.lambda_reg * self.item_features[i])
# 计算训练误差
predictions = self.global_bias + self.user_bias[:, np.newaxis] + \
self.item_bias[np.newaxis, :] + \
np.dot(self.user_features, self.item_features.T)
mask = matrix > 0
rmse = np.sqrt(mean_squared_error(matrix[mask], predictions[mask]))
# 早停机制
if self.early_stopping:
if rmse < best_rmse:
best_rmse = rmse
best_epoch = epoch
# 保存最佳模型
self.best_user_features = self.user_features.copy()
self.best_item_features = self.item_features.copy()
self.best_user_bias = self.user_bias.copy()
self.best_item_bias = self.item_bias.copy()
elif epoch - best_epoch >= self.patience:
print(f"早停机制触发,最佳RMSE: {best_rmse:.4f}")
self.user_features = self.best_user_features
self.item_features = self.best_item_features
self.user_bias = self.best_user_bias
self.item_bias = self.best_item_bias
break
def predict(self, user_id, item_id):
"""预测用户对物品的评分"""
user_idx = user_id - 1
item_idx = item_id - 1
prediction = self.global_bias + self.user_bias[user_idx] + self.item_bias[item_idx] + \
np.dot(self.user_features[user_idx], self.item_features[item_idx])
return max(1.0, min(5.0, prediction))
# LFM推荐函数
def lfm_recommendation(lfm_model, user_id, user_movie_matrix, movies_df, top_n=5):
"""基于LFM的推荐"""
# 获取目标用户已评分的电影
user_ratings = ratings_df[ratings_df['user_id'] == user_id]
rated_items = set(user_ratings['item_id'].values)
# 获取所有电影ID
all_items = set(user_movie_matrix.columns)
candidate_items = all_items - rated_items
# 计算预测评分
predictions = {}
for item_id in candidate_items:
predicted_rating = lfm_model.predict(user_id, item_id)
predictions[item_id] = predicted_rating
# 排序并返回结果
sorted_predictions = sorted(predictions.items(), key=lambda x: x[1], reverse=True)
top_predictions = sorted_predictions[:top_n]
# 添加电影标题
recommendations = []
for item_id, predicted_rating in top_predictions:
title = movies_df[movies_df['item_id'] == item_id]['title'].iloc[0]
recommendations.append({
'item_id': item_id,
'title': title,
'predicted_rating': round(predicted_rating, 2)
})
return recommendations
4.3 实验评估阶段
4.3.1 数据划分与模型训练
python
# 划分训练集和测试集
from sklearn.model_selection import train_test_split
# 转换为numpy数组
matrix = user_movie_matrix.values
# 划分数据
train_matrix, test_matrix = train_test_split(matrix, test_size=0.2, random_state=42)
# 训练LFM模型
lfm = LatentFactorModel(n_factors=50, lambda_reg=0.01, alpha=0.005, n_epochs=50)
lfm.fit(train_matrix)
# 计算相似度矩阵
user_similarity = calculate_user_similarity(user_movie_matrix)
item_similarity = calculate_item_similarity(user_movie_matrix)
4.3.2 模型评估
python
# 评估函数
def evaluate_model(model, test_matrix, model_type='user_cf',
user_similarity=None, item_similarity=None, lfm_model=None):
"""评估推荐模型性能"""
predictions = []
actual_ratings = []
# 只测试前1000条记录以节省时间
test_sample = []
for i in range(test_matrix.shape[0]):
for j in range(test_matrix.shape[1]):
if test_matrix[i, j] > 0:
test_sample.append((i, j, test_matrix[i, j]))
if len(test_sample) >= 1000:
break
if len(test_sample) >= 1000:
break
for i, j, r in test_sample:
user_id = i + 1
item_id = j + 1
if model_type == 'user_cf':
# User-CF预测
similar_users = user_similarity.loc[user_id].sort_values(ascending=False)
similar_users = similar_users.drop(user_id).head(20)
item_ratings = ratings_df[ratings_df['item_id'] == item_id]
weighted_sum = 0.0
similarity_sum = 0.0
for neighbor_id, similarity in similar_users.items():
neighbor_rating = item_ratings[item_ratings['user_id'] == neighbor_id]
if not neighbor_rating.empty:
rating = neighbor_rating['rating'].iloc[0]
weighted_sum += similarity * rating
similarity_sum += abs(similarity)
if similarity_sum > 0:
pred = weighted_sum / similarity_sum
else:
pred = ratings_df['rating'].mean()
elif model_type == 'item_cf':
# Item-CF预测
user_ratings = ratings_df[ratings_df['user_id'] == user_id]
liked_items = user_ratings[user_ratings['rating'] >= 3]
weighted_sum = 0.0
similarity_sum = 0.0
for _, liked_item in liked_items.iterrows():
liked_item_id = liked_item['item_id']
user_rating = liked_item['rating']
if item_id in item_similarity.index:
similarity = item_similarity.loc[liked_item_id, item_id]
weighted_sum += similarity * user_rating
similarity_sum += abs(similarity)
if similarity_sum > 0:
pred = weighted_sum / similarity_sum
else:
pred = ratings_df['rating'].mean()
elif model_type == 'svd':
# SVD预测
pred = np.dot(model[0][i], model[1][:, j])
pred = max(1.0, min(5.0, pred))
elif model_type == 'lfm':
# LFM预测
pred = lfm_model.predict(user_id, item_id)
predictions.append(pred)
actual_ratings.append(r)
# 计算评估指标
mae = mean_absolute_error(actual_ratings, predictions)
rmse = np.sqrt(mean_squared_error(actual_ratings, predictions))
return mae, rmse, len(predictions)
# 评估各个模型
print("开始评估模型性能...")
# 评估User-CF
user_cf_mae, user_cf_rmse, user_cf_count = evaluate_model(
None, test_matrix, 'user_cf', user_similarity=user_similarity
)
# 评估Item-CF
item_cf_mae, item_cf_rmse, item_cf_count = evaluate_model(
None, test_matrix, 'item_cf', item_similarity=item_similarity
)
# 评估SVD
svd_model = (user_features, item_features)
svd_mae, svd_rmse, svd_count = evaluate_model(
svd_model, test_matrix, 'svd'
)
# 评估LFM
lfm_mae, lfm_rmse, lfm_count = evaluate_model(
None, test_matrix, 'lfm', lfm_model=lfm
)
# 打印评估结果
print("\n模型性能评估结果:")
print("-" * 50)
print(f"{'算法':<10} {'MAE':<10} {'RMSE':<10} {'有效预测数':<10}")
print("-" * 50)
print(f"{'User-CF':<10} {user_cf_mae:<10.4f} {user_cf_rmse:<10.4f} {user_cf_count:<10}")
print(f"{'Item-CF':<10} {item_cf_mae:<10.4f} {item_cf_rmse:<10.4f} {item_cf_count:<10}")
print(f"{'SVD':<10} {svd_mae:<10.4f} {svd_rmse:<10.4f} {svd_count:<10}")
print(f"{'LFM':<10} {lfm_mae:<10.4f} {lfm_rmse:<10.4f} {lfm_count:<10}")
4.3.3 推荐结果生成
python
# 选择目标用户
target_user_id = 4
# 获取用户历史高评分电影
user_rated_movies = ratings_df[ratings_df['user_id'] == target_user_id]
high_rated_movies = user_rated_movies[user_rated_movies['rating'] >= 4].sort_values(
'rating', ascending=False
).merge(movies_df, on='item_id', how='left')[['item_id', 'title', 'rating']]
print(f"\n用户 {target_user_id} 的历史高评分电影(评分≥4分):")
print(high_rated_movies.head(10))
# 生成推荐结果
print(f"\n为用户 {target_user_id} 生成推荐:")
# User-CF推荐
user_cf_recs = user_based_recommendation(
target_user_id, user_movie_matrix, user_similarity, movies_df, top_n=10
)
# Item-CF推荐
item_cf_recs = item_based_recommendation(
target_user_id, user_movie_matrix, item_similarity, movies_df, top_n=10
)
# SVD推荐
svd_recs, _ = svd_recommendation(
target_user_id, user_movie_matrix, movies_df, top_n=10
)
# LFM推荐
lfm_recs = lfm_recommendation(
lfm, target_user_id, user_movie_matrix, movies_df, top_n=10
)
# 打印推荐结果
print("\n=== User-CF推荐结果 ===")
for i, rec in enumerate(user_cf_recs, 1):
print(f"{i}. 电影ID: {rec['item_id']}, 标题: {rec['title']}, 预测评分: {rec['predicted_rating']}")
print("\n=== Item-CF推荐结果 ===")
for i, rec in enumerate(item_cf_recs, 1):
print(f"{i}. 电影ID: {rec['item_id']}, 标题: {rec['title']}, 预测评分: {rec['predicted_rating']}")
print("\n=== SVD推荐结果 ===")
for i, rec in enumerate(svd_recs, 1):
print(f"{i}. 电影ID: {rec['item_id']}, 标题: {rec['title']}, 预测评分: {rec['predicted_rating']}")
print("\n=== LFM推荐结果 ===")
for i, rec in enumerate(lfm_recs, 1):
print(f"{i}. 电影ID: {rec['item_id']}, 标题: {rec['title']}, 预测评分: {rec['predicted_rating']}")
五、结果分析
5.1 算法性能对比
5.1.1 评分预测性能
通过实验得到的各算法性能指标如下表所示:
| 算法 | MAE | RMSE | 有效预测数 | 排名 |
|---|---|---|---|---|
| Item-CF | 0.8437 | 1.1129 | 1000 | 1 |
| User-CF | 0.8483 | 1.0694 | 1000 | 2 |
| LFM | 0.9215 | 1.1873 | 1000 | 3 |
| SVD | 1.4216 | 1.7533 | 1000 | 4 |
分析:
- Item-CF 表现最佳:MAE 为 0.8437,在所有算法中预测精度最高
- User-CF 紧随其后:MAE 为 0.8483,与 Item-CF 非常接近
- LFM 表现良好:MAE 为 0.9215,在矩阵分解算法中表现不错
- SVD 表现较差:MAE 为 1.4216,可能是因为对缺失值处理不当
5.1.2 算法运行效率
| 算法 | 训练时间 | 预测时间 | 空间复杂度 | 适用场景 |
|---|---|---|---|---|
| User-CF | 快 | 中 | O(n²) | 小规模用户 |
| Item-CF | 中 | 快 | O(m²) | 小规模物品 |
| SVD | 中 | 快 | O(nk + mk) | 大规模数据 |
| LFM | 慢 | 快 | O(nk + mk) | 大规模数据 |
5.2 推荐结果分析
5.2.1 目标用户推荐质量
以用户 ID=4 为目标用户,其历史高评分电影多为科幻、动作、冒险类型,如《星球大战》《接触未来》《空军一号》等。
User-CF 推荐结果:
- 推荐了《黑衣人》《尽善尽美》《一脱到底》等电影
- 推荐质量与用户历史偏好高度一致
- 预测评分普遍较高,最高达到 5.0 分
- 推荐电影类型相对集中,多样性一般
Item-CF 推荐结果:
- 推荐了《黑衣人》《玩具总动员》《教父》等作品
- 覆盖了与用户偏好相似的类型,还纳入了经典电影
- 预测评分同样维持在较高水平
- 推荐电影类型更加丰富,多样性优于 User-CF
SVD 推荐结果:
- 推荐了《绝地归来》《洛城机密》《圣徒》等
- 与用户历史偏好存在一定差异
- 预测评分普遍偏低,最高仅 1.76 分
LFM 推荐结果:
- 推荐了《星球大战 V》《帝国反击战》《夺宝奇兵》等
- 推荐结果与用户历史偏好比较一致
- 预测评分相对合理,处于 3.5-4.2 分之间
5.2.2 推荐多样性分析
- Item-CF 多样性最好:涵盖科幻、动画、犯罪等多种类型
- User-CF 多样性一般:主要集中在科幻和喜剧两种类型
- LFM 多样性较好:以科幻、冒险为主,兼顾一定拓展
- SVD 多样性较差:推荐结果类型归属不够明确
5.3 算法优缺点分析
5.3.1 User-CF 算法
优点:
- 能够发现用户的新兴趣
- 对新物品友好
- 算法逻辑简单直观
缺点:
- 计算复杂度较高
- 受数据稀疏性影响严重
- 存在冷启动问题
5.3.2 Item-CF 算法
优点:
- 计算相对稳定
- 可解释性强
- 推荐结果更符合用户兴趣
缺点:
- 对新物品不友好
- 容易出现热门物品过度推荐
- 受流行度影响
5.3.3 SVD 算法
优点:
- 能够挖掘潜在特征
- 对稀疏数据处理能力强
- 空间复杂度低
缺点:
- 可解释性差
- 对参数敏感
- 对缺失值处理不合理
5.3.4 LFM 算法
优点:
- 建模能力突出
- 支持偏置项
- 具备正则化机制
缺点:
- 训练时间长
- 参数调优复杂
- 可解释性差
5.4 适用场景分析
- User-CF:社交推荐场景、兴趣探索场景、新物品较多的场景
- Item-CF:电子商务场景、媒体推荐场景、用户兴趣稳定的场景
- 矩阵分解类算法:大规模数据场景、深度个性化推荐场景、混合推荐系统
六、实验结论与启示
6.1 主要结论
- 协同过滤算法在中小规模数据集上表现优异:Item-CF 和 User-CF 的 MAE 均在 0.85 以下
- 矩阵分解算法潜力巨大:LFM 表现良好,SVD 需要进一步优化
- 不存在绝对最优的推荐算法:不同算法各有优缺点,需根据具体场景选择
- 数据质量对推荐算法性能影响巨大
6.2 实践启示
- 算法选择需因地制宜:结合数据规模、用户行为特点、业务需求选择算法
- 混合推荐是未来趋势:融合不同算法优势,提升推荐效果
- 特征工程至关重要:引入额外信息,弥补评分数据不足
- 持续优化是核心要求:推荐系统需要不断迭代优化
6.3 改进方向
- 算法优化 :
- 尝试更复杂的矩阵分解算法(BiasSVD、SVD++ 等)
- 引入深度学习模型(神经协同过滤 NCF)
- 搭建混合推荐系统
- 特征工程 :
- 引入用户人口统计学特征
- 挖掘电影内容特征
- 考虑时间因素
- 评估体系 :
- 完善评估指标(覆盖率、多样性、新颖性等)
- 开展在线 A/B 测试
- 建立用户反馈机制
七、实验总结
本次实验以 MovieLens-100K 数据集为基础,深入开展了推荐算法的理论研究与实践探索:
- 理论层面:深入理解了协同过滤和矩阵分解算法的核心原理
- 实践层面:成功实现了四种推荐算法的代码编写和模型训练
- 评估分析:全面评估了不同算法的性能,分析了优缺点和适用场景
- 报告撰写:形成了结构完整、逻辑严谨的实验报告
实验结果表明,在 MovieLens-100K 数据集上,Item-CF 和 User-CF 算法的推荐效果最佳,LFM 算法表现良好,而 SVD 算法的性能有待进一步优化。这些结果为推荐系统的实际搭建提供了重要参考。
未来研究可进一步探索更先进的推荐算法,如深度学习推荐模型,同时深入研究推荐算法在实际业务场景中的落地应用,提升推荐系统的实用价值。