5 分钟写一个推荐算法库

导读:5分钟读懂入门推荐算法库:surprise

框架设计

具体的设计从三方面来完成:数据载入,算法设计,结果评估。

其中每个部分我们又可以进一步完善,下面分三部分去介绍这三个内容的细节设计,具体的实现后面会随着我的整理逐渐给出。大家也可以参考 surprise 的源码去自己分析,然后写一写。

数据载入

数据载入模块,需要支持特定数据集的自动下载,自动解压和处理;

然后可以支持用户自定义的数据集的载入,以及处理成特定格式;

最后应当包括自动划分训练集,测试集的部分。

自动下载数据

以 movielens 为例,为了避免 Python 导致的问题,选择 six 模块来进行下载,提前设置好 movielens 的下载 URL:

from six.moves.urllib.request import urlretrieve
import zipfile


tmp_file_path = join(get_dataset_dir(), 'tmp.zip')
urlretrieve(dataset.url, tmp_file_path)


with zipfile.ZipFile(tmp_file_path, 'r') as tmp_zip:
    tmp_zip.extractall(join(get_dataset_dir(), name))


os.remove(tmp_file_path)

这里以 surprise 源码中的部分代码为例,get_dataset_dir() 是一个获取当前工作路径的函数,然后用 six 模块中的 urlretrieve 函数进行下载,接着利用 zipfile 进行解压,最后删除下载的临时解压文件。

这是一个简单的自动下载数据集的方式,我们可以进一步优化该模块。如多个数据集的设置,由用户选择,判断数据集是否存在等。

自定义数据载入

自定义的数据我们默认为三列数据,每行按照 user item rating 为序。那么将其读取进来的方式就很简单:

with open(os.path.expanduser(file_name)) as f:
    raw_ratings = [line.strip().split() for line in f.readlines()]

但是到这一步还有许多需要优化的内容,如用户输入的格式不是 user item rating 的情况下,或者需要跳过前几行等。

划分训练集和测试集

训练集和测试集的划分,大家应该都很理解。在大多数情况下,我们都是把训练集和测试集按照 4:1 进行划分,参考 surprise 中的源码,其设计的方案是 k-折交叉验证法,默认设置的 k 值是 5,其实也相当于按照 4:1 进行划分。

start, stop = 0, 0
    for fold_i in range(self.n_splits):
        start = stop
        stop += len(indices) // self.n_splits
        if fold_i < len(indices) % self.n_splits:
            stop += 1


        raw_trainset = [data.raw_ratings[i] for i in chain(indices[:start],
                                                               indices[stop:])]
        raw_testset = [data.raw_ratings[i] for i in indices[start:stop]]


        trainset = data.construct_trainset(raw_trainset)
        testset = data.construct_testset(raw_testset)


        yield trainset, testset

这段代码从源码中取得,是在构建一个生成器,每次生成 k 折交叉验证中的一组训练集和测试集。

算法设计

算法设计中,surprise 提供了各种 knn 方法,也就是基于邻域的协同过滤,另外还提供了 SVD,SVD++ 等矩阵分解的方法。

对于算法的设计,主要是接口清晰,统一,具体内部的实现我们可以根据自己的需要,进行特定的设计。感兴趣的同学也可以看一下源码的方法,后面的文章中我就是参考源码的实现,结合自己的理解去进行 coding。

我希望感兴趣的朋友也可以自己独立完成编码,整个工作量不大,所有代码总计看了一下,几千行的样子,自己完整的写一遍有利于自己对模块之间调用进行熟悉。

结果评估

在 surprise 当中提供了 rmse,mae 等指标进行判断,因为原始数据集中的标签是 rating,所以这里选择了直接去学得一个拟合函数,来预估用户的评分。

def rmse(predictions, verbose=True):
    if not predictions:
        raise ValueError('Prediction list is empty.')


    mse = np.mean([float((true_r - est)**2) for (_, _, true_r, est, _) in predictions])
    rmse_ = np.sqrt(mse)


    if verbose:
        print('RMSE: {0:1.4f}'.format(rmse_))


    return rmse_

这里就是一个计算 rmse 的方法,prediction 是一个从给定算法中得到的返回值,我们可以清晰的看到真实的标签得分是 true_r,而算法得到的预测分数为 est,然后按照 mse 的计算方式求得结果,在开方得到 rmse。

这是以 rmse 为例,但是从模型的设计方面考虑,如果我们要计算多个指标,或者由用户选择来计算哪些指标,就应该设计的更灵活点。

那么 python 的内置函数 getattr 就可以解决这个问题。

for m in measures:
    f = getattr(accuracy, m.lower())
    test_measures[m] = f(predictions, verbose=0)

在 measures 中,是一个由需要获得的指标组成的列表,例如 [rmse, mse],这就表示需要计算 rmse 和 mse 两个指标的结果。

总结

今天简单的介绍了一下推荐系统中非常基础的 surprise 库,然后解析了一下它的主体架构,后面我们自己逐渐细化进去,完成一个自己的推荐系统库,在这个过程中也可以锻炼自己的代码结构的设计能力。

推荐阅读:

2020Python招聘内推渠道开启啦!

老司机教你5分钟读懂Python装饰器

用Python实现粒子群算法

抄底美股?用Python分析美股实际收益率

▼点击成为社区会员   喜欢就点个在看吧

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值