来源 | 机器学习与推荐系统

surprise 支持的每个算法本身思路并不复杂,代码也不晦涩难懂,我们主要的目的是理解它的架构,学习框架各个部分的交互。

这篇文章是想从一个整体的视角,以作者最初的思路为主线进行介绍,观察并思考如何一步一步的让模型 run 起来。

先搞个模型跑起来

我们首先从一个总体性的代码看一下,很简单的几行代码,开始我们的 surprise 之旅。

这里需要导入的部分,我都已经重写过了,但是大家可以在自己本地的代码上尝试一下,直接利用 surprise 库就可以运行一个简单的 KNN 算法,本质上也就是基于邻域的协同过滤算法。按照我在代码上标注出来的红线部分,分别给对应的四个 import 模块,前面加上 surpris. 的路径就可以从 surprise 中进行导入。

这里需要提一下,我用的是自己之前已经在 movielens 官网下载的数据集,大家可以自己直接下载,也可以在网上找一下教程,surprise 支持自动下载 movielens 的数据集。

接下来我们只看 surprise_code() 函数,这个函数就是我们需要学习的所有内容,从这个例子开始,我们要去一步步深扒 surprise 的执行过程。

def surprise_code():reader = Reader(line_format="user item rating", sep=',', skip_lines=1)data = Dataset.load_from_file('./ml-latest-small/ratings.csv', reader)algo = KNNBasic()perf = cross_validate(algo, data, measures=['RMSE', 'MAE'], cv=2, verbose=0)
for keys in perf:print(keys, ": ", perf[keys])

对核心的 surprise_code() 函数,可以分为两个部分来看:数据载入,算法执行并检测结果。

数据载入,由 Reader 和 Dataset 两个类来提供功能,具体的思路是由 Reader() 提供读取数据的格式,然后 Dataset 按照 Reader 的设置来完成对数据的载入。

算法执行并检测结果,这里由一个 cross_validate() 来完成,提前导入需要执行的算法并实例化,然后将数据,算法,要检测的指标等都传入 cross_validate(),它会完成对算法的训练拟合,然后进行预测结果,再对结果进行验证,最终返回目标的检测指标对应的结果。

所以我们可以看到直接调用接口是很容易跑起来一个模型的,仅这么几行简单的代码就可以将一个算法完整的运行起来。但是如果要深入到代码的执行细节上,就需要捋顺它们的关系,然后抽丝剥茧一点点展开。

我们可以提前将上面的算法执行并检测结果分成了两部分,也就是将整个工作流程划分为三部分:数据载入,算法设计,结果评估。这样子更加细化的一步当然没问题,逻辑上这样子也更容易理解。

现在捋顺了算法的执行思路以后,我们开始从数据集的载入开始去分析源码。

trick:在正式细节代码前,分享一些关于我学习源码的方法,不一定适合所有人,也不一定适合所有源码,仅供大家参考:

首先,要像我们一样完成一个非常简单的 demo,如这一小节的标题一样,先搞个模型跑起来。至少我们得会用它,能用起来,这样子我们才能分析下去。

其次,我们再捋顺模型的流程,划分为几个主要的部分,按照这个逻辑顺序,从最初的部分开始,尝试自己完成该模块的功能。导入自己写的部分,替代掉源码的那一部分,看看前面的 demo 能不能继续运行,检查结果是否一致。

最后,不要在分析的时候,拘泥于细节,先完成该模块的主要功能。如果这部分功能与其它模块相关,可以先导入相关的模块,直接使用。不要尝试一步将某一个模块写的尽善尽美。

这三个提到的内容,我们在接下来的文章可以再进一步体会。

从第一部分的数据载入开始

我们前面分析了数据载入部分,由 Reader 和 Dataset 两个类来提供功能。接下来要做的就是捋顺这部分内容,然后自己尝试写出来对应的模块,并且替代进去,看看我们前面的代码能不能继续正常运行。

当我们到了这一步的时候,首先就是打开这两个模块,看一看代码,了解一下它们的功能。在【第二篇文章:推荐实践(2):数据集的载入与切割】中,对这两部分的内容进行了仔细分析,我在这里就总体性的介绍一下,不深入到代码细节上去了。

reader = Reader(line_format="user item rating", sep=',', skip_lines=1)

对于这个 Reader() 类,主要的功能是设置一个读取器。从 Reader 的使用也可以看出来,要求的输入是每行的格式,每行的分隔符,要忽略的行数。

从这个类实例时的输入上,我们可以判断出来,这个 Reader() 类的作用是构造一个读取器对象 reader,这个读取器 reader 包含了一些如何去读数据的属性。比如 reader 知道每行的数据是按照 “user item rating” 来分布的,知道每行数据由符号 "," 分割开,知道第一行的数据应该被跳过。

所以我们在构建了这个 reader 以后,就可以将它传给 Dataset() 类,来辅助我们从数据集中,按照我们想要的格式读取出来数据内容。

data = Dataset.load_from_file('./ml-latest-small/ratings.csv', reader)

由于这里我们选择了使用自己已经下载的数据集,调用的就是 Dataset.load_from_file() 方法。可以看到的是,这个方法的输入有两个参数,第一个是数据集的路径,第二个就是刚刚实例化的读取器 reader。

所以这个 load_from_file() 在读取数据时,就会按照 reader 的定义的格式来读取,最终返回一个自定义的数据格式。其实如果看了代码,我们可以看到这里返回的数据格式是:dataset.DatasetAutoFolds,但是正如我们前面说的,对于源码不要陷入细节。我们知道这两步对原始的数据集文件进行了处理,得到了后续可以处理的数据格式,就 OK 啦。

进行结果交叉验证

在完成数据集的载入以后,我们选择的是利用 cross_validate() 执行算法并交叉检验。这一部分的内容,我们分为两部分去介绍。

首先忽略掉算法的实现,直接调用算法的接口。这也是一个很实用的 trick,适当的时候忽略掉一些代码实现,即使你接下来要用到它,也可以直接调源码的接口。所以我们这里忽略了 KNN 算法的实现,直接调用它来实现训练拟合以及后续在测试集上的预测。

那么 cross_validate() 里面是什么呢?我们看一下 validate 中的内容:

validate 中有两个函数,分别是 cross_validate() 和 fit_and_score()。我们简单的介绍一下它们的功能,让大家可以继续没有障碍的阅读当前这篇文章。

algo = KNNBasic()
perf = cross_validate(algo, data, measures=['RMSE', 'MAE'], cv=2, verbose=0)

可以看到 cross_validate() 是被调用的外部接口,很容易可以猜到,fit_and_score() 是在 cross_validate() 中被调用的。

对 cross_validate() 而言,它的输入有算法对象,数据集,需要测量的指标,交叉验证的次数等。这里简单的介绍一下它的内部逻辑。它对输入的数据 data,分成 cv 份,然后每次选择其中一份作为测试集,其余的作为训练集。在数据集划分完后,对它们分别调用 fit_and_score(),去进行算法拟合。

这里注意一个小细节,对数据集的划分不是静态全部划分完,然后分别在数据集上进行训练和验证,而是利用输入的 data 构造一个生成器,每次抛出一组划分完的结果。

对 fit_and_score() 函数,它对输入的算法在输入的训练集上进行拟合,然后在输入的测试集上进行验证,再计算需要的指标。

在进行到这里的时候,同样忽略掉对预测结果进行指标测量的步骤,直接调用 surprise 中的 accuracy 来进行处理。当然到后面我们会补充这些内容,这里要注意的重点是如何进行交叉验证。

这一部分内容的核心是,在有了我们第 2 节输入的数据后,该如何进行数据集的划分以及如何进行算法的训练和验证。所以我们关注的重点是数据集在进行 k 折交叉验证时如何划分,又如何调用接口完成算法在数据集上的训练和测试。

说这一段的意思是想告诉大家,在阅读源码,或者仿写源码时,需要把握住自己在这一步骤的核心思路,屏蔽掉暂时不重要,或者对当前步骤不是很关键的内容。哪怕只是调用各个接口来完成自己当前步骤的任务,只要你把握住了它们的交互关系,处理流程就 OK。

再补充忽略的算法部分

打开上面的 fit_and_score() 函数,我们可以看到对 algo 的使用只有两句代码,一个是训练阶段的 algo.fit(trainset) ,一个是测试阶段的 algo.test(testset)。前者是对算法在训练集上进行拟合,而后者是对算法在测试集上进行测试。

针对 knn 的算法而言,算法的实现上是比较简单的。主要包括了一个 fit() 方法,和一个 estimate() 方法。这里主要是需要对类间的继承关系进行梳理。

在 surprise 中,所有的算法类都继承于一个父类:algo_base(),这个类中抽象出来了一些子类都容易用到的方法,有的给出了具体的实现,有的只是抽象出了一个接口,如 fit() 方法,在 algo_base() 中和其子类 knn() 中都有定义。

这里帮助大家再进一步梳理算法类之间的关系。对 algo_base() 而言,其是一切 surprise 中的算法的父类。那么以 knn 算法为例,这里就不是由 knn() 直接继承 algo_base() 了,而是先有一个 SymmetricalAlgo() 类继承 algo_base(),然后由对应的 knn() 类继承 SymmetricalAlgo() 类。

这里的 SymmetricalAlgo() 的主要工作是处理 knn 中经常需要考虑的一个问题。基于用户还是基于物品的协同过滤。SymmetricalAlgo() 中主要有两个方法,一个是前面一直提到的 fit() 方法,这里的 fit() 方法主要是对 n_x 和 n_y 等做出调整,判断是基于用户相似性还是基于物品相似性,然后调整对应的数据指标。

另外一个方法则是 switch() 方法,顾名思义,switch() 方法同样是调整对应的指标,调整的依据则是判断是基于用户相似性还是物品相似性,调整后的结果用来在测试时使用。

关于其它的算法我们就不一一展开去分析了,授人以鱼不如授人以渔,通过这一个算法的分析,我们就可以明白如何分析算法的具体实现了,也就可以很容易的了解其它算法的功能组成。

在解决了算法部分的问题后,我们了解了算法之间类的继承关系,以及父类提供的接口和可以使用的方法。接下来即使再写其它算法,我们也可以仿照这个思路,保证这些接口的基础上,实现自己的算法代码。

指标测量和数据集的格式

我们在前面第三部分提到,对于预测结果如何进行指标计算的内容可以暂时忽略,这里我们就补充这一部分内容。之所以选择在这里进行补充,我们可以看到,通过前面几步,已经搭建起来了一个基本完整的 demo。其中只有少量内容调用了源码,对预测结果的指标计算就是其中一个。

指标测量部分唯一需要注意的是预测结果的返回形式,也就是前面 Algo_base() 中 test() 方法返回的结果:predictions。

然后就是对计算的几类指标的定义需要了解:MSE,RMSE,MAE,FCP。前三类都是比较常见的指标,FCP 在源码中给出了一篇 paper 作为 reference,其中的定义也很清晰,我们参考 paper 中的定义便可。

具体的计算方法知道了以后,代码的实现就是很简单的了。利用 numpy 可以快速的计算出想要的结果。

至此,整个 demo 可以运行完毕。但是还有一个前面留下的坑需要填一下,就是前面提到对于数据集的格式的问题。在前面提到的时候,我们说这些内容可以忽略过去。但是,其实在 surprise 中对数据格式的定义还是很值得学习的。

surprise 定义了一个 Trainset() 类,用来储存所有与数据集相关的内容。比如用户数量,物品数量,评分数量等比较简单的内容,以及将数据集中的 user ID 转化为新定义的数据结构中的内部编号 inner ID,获取全局平均评分等稍复杂的功能。

通过定义一个数据集的类,可以对数据集进行一次处理,然后需要相应指标时只需直接调用。剩下了很多的运行时间,而且让代码更简洁。

总结

这篇文章本身算是一篇疏导性的总结,结合之前的文章,大家可以自己复现出来一个 surprise 中的 knn 算法,而且其它部分的接口也介绍的非常清晰。对于想要在 surprise 上继续学习其它算法源码的朋友,可以轻松的按照我们之前的分析基础,继续自己的学习;对于想要进行魔改,加入一些自己想要的算法的朋友,目前的介绍也已经清晰的解释了各个接口,大家对应来封装自己的算法就可以了。

另外一方面,本篇文章也从如何阅读源码的角度为大家分享了一些我自己的经验,或许有些地方可以帮助到大家。从如何开始阅读源码,到从一个小 demo 逐渐剖析,暂时忽略掉一些不重要的模块,一步步的完成自己的代码对源码的替代,以写代读。

更严格的讲,这种以写代读比较适合代码量不超过一万行的小型库。这种级别的代码量,我们可以通过自己完整的写一遍来加深理解。但是更高量级的代码量,就不太适合写了,还是以梳理逻辑架构为主了。

今日福利

遇见陆奇

同样作为“百万人学 AI”的重要组成部分,2020 AIProCon 开发者万人大会将于 7 月 3 日至 4 日通过线上直播形式,让开发者们一站式学习了解当下 AI 的前沿技术研究、核心技术与应用以及企业案例的实践经验,同时还可以在线参加精彩多样的开发者沙龙与编程项目。参与前瞻系列活动、在线直播互动,不仅可以与上万名开发者们一起交流,还有机会赢取直播专属好礼,与技术大咖连麦。

门票限量大放送!今日起点击阅读原文报名「2020 AI开发者万人大会」,使用优惠码“AIP211”,即可免费获得价值299元的大会在线直播门票一张。限量100张,先到先得!快来动动手指,免费获取入会资格吧!

点击阅读原文,直达大会官网。

  • 你点的每个“在看”,我都认真当成了AI

小白也能看懂:一文学会入门推荐算法库 surprise相关推荐

  1. 小白也能看懂的 Web 前端入门文章(一个浏览器的自白)

    标题:一个浏览器的自白 小 C:"Nginx 大哥,你在吗?" Nginx:"Chrome 小老弟,我在呢!你准备好了吗?" 小 C:"我准备好了,开 ...

  2. 小白都能看懂的C语言入门教程

    文章目录 C语言入门教程 1. 第一个C语言程序HelloWorld 2. C语言的数据类型 3. 常量变量的使用 4. 自定义标识符#define 5. 枚举的使用 6. 字符串和转义字符 7. 判 ...

  3. 不会真的有人看不懂 Linux 小白都能看懂的大数据入门(一) 图文

    一.概述 1.1 Linux的历史 操作系统,英语Operating System简称为OS.说道操作系统就需要先讲一讲Unix,UNIX操作系统,是一个强大的多用户.多任务操作系统,支持多种处理器架 ...

  4. 双碑零基础意大利语学习 小白也能看懂的意大利语入门知识

    问候语 1)意大利人熟人之间见面,一般用"ciao",类似于英语中的"hi".[读作.查哦.] 再见很简单,就是连读两遍"ciao". 2) ...

  5. python进阶(小白也能看懂)——装饰器浅谈(一)

    python进阶(小白也能看懂)--装饰器(一) 第四篇 文章目录 python进阶(小白也能看懂)--装饰器(一) 1.函数基础知识 例子1.1 例子1.2 例子1.3 例子1.4 2.不带参数的装 ...

  6. python进阶(小白也能看懂)——Map、Filter、Reduce

    python进阶(小白也能看懂)--Map.Filter.Reduce 第三篇 Map.Filter.Reduce是python中常用的函数,使用这些函数能够给我们带来很多便捷. Map map(fu ...

  7. python进阶(小白也能看懂)——*args与**kwargs的使用

    python进阶(小白也能看懂)--*args与**kwargs的使用 第一篇 理解*args与**kwargs在定义函数时的作用 假设你写了一个函数multiply(函数定义在下面),专门用来处理两 ...

  8. 随机森林的特征 是放回抽样么_机器学习超详细实践攻略(10):随机森林算法详解及小白都能看懂的调参指南...

    一.什么是随机森林 前面我们已经介绍了决策树的基本原理和使用.但是决策树有一个很大的缺陷:因为决策树会非常细致地划分样本,如果决策树分得太多细致,会导致其在训练集上出现过拟合,而如果决策树粗略地划分样 ...

  9. 小白都能看懂的实战教程 手把手教你Python Web全栈开发(DAY 3)

    小白都能看懂的实战教程 手把手教你Python Web全栈开发 Flask(Python Web)实战系列之在线论坛系统 第三讲 这是小白都能看懂的实战教程 手把手教你Python Web全栈开发 的 ...

最新文章

  1. cp -r dir1/. dir2 表示将dir1下的文件复制到dir2,不包括dir1目录
  2. ZOC7 for Mac连接CentOS7无法输入中文问题
  3. Calendar日历小程序
  4. iptables 智能限速方案
  5. css知识点笔记-常见特性
  6. C语言详解 - 数组
  7. Java实现按名称、日期、大小对文件进行排序
  8. c++11 常量表达式
  9. centos6.5搭建php网站,Centos6.5下搭建web环境(Apache+mysql+php+phpMyAdmin)
  10. Android dp转px,sp转px
  11. 19.内在摄像机校准——介绍,理想与真实固有参数之比,改善内在参数_1
  12. 安卓虚拟机_[手机软件] 这款应用牛逼了,安卓手机上的虚拟机 - 虚拟大师
  13. maven配置私服后Cannot download sources, 无法下载源码
  14. Babuk/AtomSilo/LockFile勒索软件免费解密工具
  15. 讯飞语音合成 如何选择发音人
  16. 生活中的十大心理学现象
  17. vue 中使用 pug
  18. 华为血压表WATCH D测量血压的数据可靠吗
  19. FileZilla的下载与安装
  20. 流程图软件lauto_流程图软件(Iauto)

热门文章

  1. 《精通 ASP.NET MVC 3 框架(第三版)》----第2章 准备工作 2.1 准备工作站
  2. SQLServer------插入数据时出现IDENTITY_INSERT错误
  3. android Spinner 例子
  4. Phabricator是什么,代码审查工具
  5. 从1.5K到18K 一个程序员的5年成长之路(二)
  6. 100道 Dubbo面试题及答案(2021最新)
  7. Oracle 12c DG备库Alert报错ORA-01110
  8. Nodejs.热部署方法
  9. ConcurrentHashMap实现原理及源码分析
  10. 各种函数调用约定及浮点数传参