最近在看《推荐系统实践》这本书,对于其中 2.4.1 基于用户的协同过滤算法和 2.4.2 基于物品的协同过滤算法进行了简易实现。
本文列举了在算法实现过程中遇到的一些情况并做了猜想与解释。
数据准备
本实验采用的数据集来自于MovieLens。
基本原理
本实验将分别采用UserCF算法和ItemCF算法,目的是为了给用户推荐电影,而不是预测用户会给某部电影打多少分。因此,ratings.csv中的打分信息可以忽略。
先读取ratings.csv中的数据,再随机将数据分为训练集Train与测试集Test。在训练集中获取训练User之间的关联信息UserSimilarity或者训练Item之间的关联信息ItemSimilarity,并根据Similarity给测试用户推荐新的电影。
Code
代码已放在对应Github上。
实验结果
UserCF
当采用不同数量的相关用户(K取值不同)的时候,推荐算法产生的precision、recall、coverage、popularity有着一定相关关系。时间花费也相差较大。如下所示:
K precision recall coverage popularity time
10 16.00% 9.38% 6.79% 4.83 19.60
10 15.81% 9.31% 6.61% 4.83 19.38
10 15.64% 9.26% 6.76% 4.84 21.02
10 15.99% 9.42% 6.62% 4.84 21.14
10 16.26% 9.92% 6.51% 4.83 20.23
10 15.31% 9.10% 6.67% 4.84 20.06
10 15.04% 9.05% 6.58% 4.85 20.29
10 16.11% 9.52% 6.69% 4.84 20.50
average:
10 15.77% 9.37% 6.65% 4.84
K precision recall coverage popularity time
50 17.80% 10.44% 2.78% 5.12 73.39
50 17.23% 10.15% 2.82% 5.12 78.35
50 16.60% 9.83% 2.83% 5.13 80.17
50 17.89% 10.54% 2.75% 5.13 79.42
50 17.18% 10.48% 2.82% 5.12 80.98
50 17.03% 10.13% 2.87% 5.12 80.02
50 16.84% 10.14% 2.85% 5.12 85.77
50 17.43% 10.30% 2.97% 5.12 80.01
average:
50 17.25% 10.25% 2.84% 5.12
若K相同,使用User-IIF算法,则从实验结果中可以看到,在coverage上有了一定提升。K=10时,结果如下:
K precision recall coverage popularity time
10 16.21% 9.51% 7.70% 4.75 26.20
10 15.35% 9.04% 7.72% 4.77 25.82
10 15.56% 9.21% 7.92% 4.77 25.59
10 15.81% 9.31% 7.55% 4.77 25.51
10 16.27% 9.93% 7.56% 4.76 26.16
10 15.37% 9.14% 7.62% 4.77 25.66
10 14.66% 8.83% 7.66% 4.77 25.62
10 16.05% 9.49% 7.45% 4.77 27.94
average:
10 15.66% 9.31% 7.65% 4.77
ItemCF
在运行ItemCF过程中,意外的发现程序耗时特别久,如下所示:
K precision recall coverage popularity time
10 15.42% 9.04% 7.28% 4.67 1587.82
与UserCF相比,除了time之外的数据相差都不大,而time则相差了60倍左右。
从数据集中分析,本数据集包含671个User,9125 个Item,Item / User = 13.60。
从代码层面分析,在某同一数据集下,UserCF和ItemCF分别能得到以下结果(Similarity函数和Recommend函数均在只执行一次的条件下测得数据):
CF | Similarity函数中循环次数 | Similarity函数运行时间 | Recommend函数中循环次数 | Recommend函数运行时间 |
---|---|---|---|---|
UserCF | 5491318 | 1.721613 | 945 | 0.011548 |
ItemCF | 58900317 | 35.749465 | 200 | 1.021870 |
ItemCF/UserCF | 10.73 | 20.77 | 0.21 | 88.49 |
可以发现,Similarity函数和Recommend函数的运行时间和内部循环次数并不十分相关,尤其当ItemCF的Recommend循环远小于UserCF的Recommend循环时,运行时间却要来的更大。
注意到这两个函数内部都额外构建了dict,分别代表User_Items关系与Item_Users关系,且都实现了相关的find、sort操作,故函数运行时间差异主要与不同Size的Dict的find、sort性能相关。