在这个信息爆炸的时代,我们每天都面临着海量的选择。想象一下,你打开了一个视频网站,却不知道该看什么好?这时候,一个贴心的电影推荐系统就显得尤为重要了。今天,让我们一起揭开电影推荐系统的神秘面纱,看看数据科学家们是如何运用ALS(交替最小二乘法)算法来实现个性化推荐的。
🧙♂️ ALS算法:推荐系统的”魔法棒”
首先,让我们来认识一下今天的主角——ALS算法。想象一下,如果推荐系统是一位魔法师,那么ALS算法就是他手中的魔法棒。这个算法的全名是Alternating Least Squares,听起来很高大上,但其实它的工作原理并不难理解。
假设我们有一个巨大的用户-电影评分矩阵,就像是一张魔法地图。但这张地图上有很多空白区域,因为不是每个用户都看过所有的电影。ALS算法的任务就是要填补这些空白,预测用户可能会给未看过的电影打多少分。
它是怎么做到的呢?简单来说,ALS算法假设每个用户和每部电影都可以用一组数字(我们称之为”潜在因子”)来表示。比如,一个用户可能喜欢动作片(因子1)和浪漫喜剧(因子2),而讨厌恐怖片(因子3)。同样,一部电影也可以用这些因子来描述它的特点。ALS算法就是通过不断调整这些因子,使得预测的评分尽可能接近实际的评分。
🎭 MovieLens数据集:我们的”演员阵容”
在这个实验中,我们使用的是著名的MovieLens数据集。这个数据集就像是我们的”演员阵容”,包含了大量用户对电影的真实评分。具体来说,我们使用的是MovieLens 100k数据集,包含了约10万条评分数据。
让我们来看看这个数据集的”剧本”:
+------+-------+------+---------+
|UserId|MovieId|Rating|Timestamp|
+------+-------+------+---------+
| 196| 242| 3.0|881250949|
| 186| 302| 3.0|891717742|
| 22| 377| 1.0|878887116|
| 244| 51| 2.0|880606923|
| 166| 346| 1.0|886397596|
+------+-------+------+---------+
这里,每一行代表一个用户对一部电影的评分。UserId是用户的唯一标识,MovieId是电影的唯一标识,Rating是用户给这部电影的评分(1-5分),Timestamp是评分的时间戳。
🎬 准备开机:数据预处理
在开始我们的”电影推荐大戏”之前,我们需要做一些准备工作。首先,我们需要将数据集分成训练集和测试集。这就像是在拍电影前先排练一遍,确保一切就绪。
train, test = spark_random_split(data, ratio=0.75, seed=123)
print ("N train", train.cache().count())
print ("N test", test.cache().count())
这段代码将数据集随机分成了两部分:75%的数据用于训练,25%的数据用于测试。这样做的目的是为了后续评估我们的模型性能。
🎥 Action!训练ALS模型
现在,让我们开始训练我们的ALS模型。这就像是开始拍摄我们的”电影推荐大片”了!
als = ALS(
rank=10,
maxIter=15,
implicitPrefs=False,
regParam=0.05,
coldStartStrategy='drop',
nonnegative=False,
seed=42,
**header
)
with Timer() as train_time:
model = als.fit(train)
print("Took {} seconds for training.".format(train_time.interval))
这里,我们设置了一些超参数:
rank=10
:这意味着我们用10个潜在因子来描述每个用户和电影。你可以把它想象成我们用10种不同的特征来描述一个人的电影偏好。maxIter=15
:这是算法最多迭代的次数。就像是我们最多拍15条片段,然后选择最好的一条。implicitPrefs=False
:这表示我们使用的是显式反馈(即用户明确给出的评分),而不是隐式反馈(比如观看时长)。regParam=0.05
:这是正则化参数,用来防止模型过拟合。就像是给演员一些即兴发挥的空间,但又不能偏离剧本太远。coldStartStrategy='drop'
:这意味着我们会丢弃那些在训练集中没有出现过的用户或电影。就像是我们只关注主演,不考虑群众演员。
训练完成后,我们得到了一个能够预测用户对电影评分的模型。接下来,我们就可以用这个模型来给用户推荐电影了!
🍿 推荐时间到!
现在,让我们用我们训练好的模型来为用户推荐电影。但是等等,我们不能推荐用户已经看过的电影,对吧?那样就太无聊了!所以,我们需要先排除用户已经看过的电影。
users = train.select(COL_USER).distinct()
items = train.select(COL_ITEM).distinct()
user_item = users.crossJoin(items)
dfs_pred = model.transform(user_item)
dfs_pred_exclude_train = dfs_pred.alias("pred").join(
train.alias("train"),
(dfs_pred[COL_USER] == train[COL_USER]) & (dfs_pred[COL_ITEM] == train[COL_ITEM]),
how='outer'
)
top_all = dfs_pred_exclude_train.filter(dfs_pred_exclude_train[f"train.{COL_RATING}"].isNull()) \
.select('pred.' + COL_USER, 'pred.' + COL_ITEM, 'pred.' + "prediction")
这段代码看起来有点复杂,但别担心,让我来解释一下:
- 首先,我们获取所有的用户和电影。
- 然后,我们做了一个”交叉连接”,得到所有可能的用户-电影组合。
- 接着,我们用模型预测这些组合的评分。
- 最后,我们排除了用户已经看过的电影,只保留未看过的电影的预测评分。
这就像是我们为每个观众定制了一份专属的电影菜单,里面只有他们没看过的新电影!
🏆 模型评估:我们的”电影”有多成功?
好了,我们的”电影推荐大片”拍摄完成了。但是,它到底表现如何呢?我们需要一些指标来评估我们的模型性能。这就像是电影上映后看票房和口碑一样。
首先,我们来看看推荐系统的常用评估指标:
print("Model:\tALS",
"Top K:\t%d" % rank_eval.k,
"MAP:\t%f" % rank_eval.map_at_k(),
"NDCG:\t%f" % rank_eval.ndcg_at_k(),
"Precision@K:\t%f" % rank_eval.precision_at_k(),
"Recall@K:\t%f" % rank_eval.recall_at_k(), sep='\n')
这里的几个指标,让我们一一解释:
- MAP (Mean Average Precision):这个指标衡量的是推荐的准确性和排序质量。值越高越好。
- NDCG (Normalized Discounted Cumulative Gain):这个指标考虑了推荐项的位置,排在前面的推荐项权重更大。值越高越好。
- Precision@K:在前K个推荐中,有多少比例是用户真正喜欢的。
- Recall@K:在用户所有喜欢的项目中,有多少比例被包含在了前K个推荐中。
接下来,我们还可以看看模型在评分预测方面的表现:
print("Model:\tALS rating prediction",
"RMSE:\t%f" % rating_eval.rmse(),
"MAE:\t%f" % rating_eval.mae(),
"Explained variance:\t%f" % rating_eval.exp_var(),
"R squared:\t%f" % rating_eval.rsquared(), sep='\n')
这里的指标包括:
- RMSE (Root Mean Square Error):预测评分与实际评分的平均差距。越小越好。
- MAE (Mean Absolute Error):预测评分与实际评分的平均绝对差。越小越好。
- Explained variance:模型解释的方差比例。越接近1越好。
- R squared:决定系数,表示模型的拟合优度。越接近1越好。
🎭 结语:推荐系统的未来
我们的ALS模型在MovieLens数据集上取得了不错的成绩,但这只是推荐系统的冰山一角。在实际应用中,还有很多因素需要考虑,比如用户的实时反馈、季节性趋势、热门事件等。
推荐系统就像是一个永不停歇的导演,不断学习用户的喜好,为每个人导演一部专属的”电影人生”。随着深度学习、强化学习等新技术的发展,未来的推荐系统将会更加智能,更加个性化。
也许有一天,推荐系统不仅能告诉你”看什么”,还能根据你的心情和当下的情境,告诉你”什么时候看”、”和谁一起看”,甚至为你量身定制一部前所未有的新电影!
让我们一起期待推荐系统的未来,也许下一秒,它就会为你推荐一部改变人生的好电影呢!
参考文献:
- Koren, Y., Bell, R., & Volinsky, C. (2009). Matrix factorization techniques for recommender systems. Computer, 42(8), 30-37.
- Harper, F. M., & Konstan, J. A. (2015). The movielens datasets: History and context. Acm transactions on interactive intelligent systems (tiis), 5(4), 1-19.
- Hu, Y., Koren, Y., & Volinsky, C. (2008). Collaborative filtering for implicit feedback datasets. In 2008 Eighth IEEE International Conference on Data Mining (pp. 263-272). IEEE.
- Rendle, S., Krichene, W., Zhang, L., & Anderson, J. (2020). Neural collaborative filtering vs. matrix factorization revisited. In Fourteenth ACM Conference on Recommender Systems (pp. 240-248).
- Smith, B., & Linden, G. (2017). Two decades of recommender systems at Amazon. com. IEEE Internet Computing, 21(3), 12-18.