使用例子

使用经典的Movielens 100k dataset数据集作为推荐的例子. 在lightFM中, 可以直接调用函数获取整理成稀疏矩阵格式的数据:

from lightfm.datasets import fetch_movielens

data = fetch_movielens(min_rating=5.0)

但在这里, 我们将从原始的数据开始, 记录从原始数据到可供lightFM模型使用的数据, 即稀疏矩阵形式(coo, csr). 从而将数据处理的方法直接使用在各种推荐数据集上.

读取数据

下载好的数据集目录中包含很多文件, 其中的u.data包含了所有数据. 文件中每一行为一个交互样本, 格式为user id | item id | rating | timestamp, 列之间以tab符分隔. 使用pandas读取数据.

import codecs
import numpy as np
import pandas as pd

inter_file = "./data/ml-100k/u.data"

data = pd.read_csv(inter_file, delimiter="\t", header=None)
data.columns = ["user_id", "item_id", "rating", "timestamp"]
data.shape
(100000, 4)

共有100000条行为数据.

转为稀疏矩阵

lightFM模型中个各种方法只接受稀疏矩阵的形式, 因此需要把这种行形式的行为数据转换为(user, item)这种稀疏矩阵的形式. 固然可以使用scipy中的方法创建可以空的系数矩阵, 然后循环行为样本, 将对应位置填值, 但lightFM中提供了包装好的类来进行处理.

而且由于lightFM中使用useritem的特征, 使得整体数据情况比较复杂. 通过lightFM中的Dataset类就能够很好地进行管理. lightfm.data.Dataset能够做到:

  • useritem自身与整数索引之间的映射关系

  • useritem特征的管理, 包括特征的顺序等

  • 生成(user, item)对的稀疏矩阵

  • 生成useritem的特征数据结构

首先创建一个Dataset.

Dataset__init__函数中有两个参数:

  • user_identity_features

  • item_identity_features

这两个参数默认值都为True. 以第一个参数为例, 作用是: Create a unique feature for every user in addition to other features. 即将每个用户本身作为一个特征, 追加到现有的user特征中, 其实就是用户的One-Hot特征.

如果没有任何useritem特征, 则这两个参数必须指定为True. 每个user, 每个item都是一个独特的特征, 只会被该useritem使用到, 其他的不会使用. 在这种情况下, lightFM算法也就等价于普通的FM算法.

在初始化完毕之后, 接下来需要将user列表item列表为模型指定, 这一步需要调用Datasetfit方法. 需要注意这里的fit方法投入的不是行为数据, 只是所有useritem分别组成的列表.

fit方法接收下面4个参数:

  • users: iterable of user ids, user列表

  • items: iterable of item ids, item列表

  • user_features: iterable of user features, optional, user feature的名称列表

  • item_features: iterable of item features, optional, item feature的名称列表

这一步的作用是对每个useritem指定一个整数ID, 这个id就是传入列表中元素的顺序. ID从0开始, 在lightFM中使用的这种整数索引, 而不是原始的user, item名称.

然后就可以通过函数看到useritem的交互矩阵的大小了.

共943个user, 1682个item.

如果后续需要增加user, item或user feature和item feature的内容, 只需要调用dataset.fit_partial, 参数形式与fit方法相同, 因为fit方法的内部也是调用了fit_partial完成的.

接下来就是生成行为矩阵(interactions matrix)了. 这就需要用到原始的行形式的行为数据. 使用dataset.build_interactions函数, 这个函数有以下的重要参数:

  • data: iterable of (user_id, item_id) or (user_id, item_id, weight).

    • 即是一个迭代器, 每个元素符合上面两种形式, 分别是行为数据与打分数据.

该函数的返回值有两个:

  • (interactions, weights)

    • 两个都是COO matrix的格式

    • 分别表示是否有交互行为, 和对应的权值. 其中weights在评分系统中有用, 在表示是否有交互行为时, 由于传入的data中每个元素的格式为(user_id, item_id), 此时生成的weights中的权值都为1, 因此与interactions是完全相同的

这一步耗时比较长.

拟合模型

在得到了稀疏矩阵形式的交互数据之后, 就可以创建模型, 并进行拟合操作了.

LightFM是一种hybrid latent representation recommender model. 在初始化时, 需要注意一下的参数:

  • no_components: int, optional

    • 隐向量的长度, 默认为10. the dimensionality of the feature latent embeddings.

  • learning_schedule: string, optional

    • 学习率的变化策略, one of ('adagrad', 'adadelta'), 默认为adagrad

  • loss: string, optional

    • 训练时使用的损失函数, 这个参数非常重要, 不同的场景需要指定不同的损失函数

    • one of ('logistic', 'bpr', 'warp', 'warp-kos')

    • logistic: useful when both positive (1) and negative (-1) interactions are present

    • bpr: Bayesian Personalised Ranking. 目标是最大化正样本与随机一个负样本之间差值. 在以下的场景中使用:

      • only positive interactions are present

      • 需要最优的ROC, AUC

    • warp: Weighted Approximate-Rank Pairwise. 在以下的场景中使用:

      • only positive interactions are present

      • optimising the top of the recommendation list (precision@k) is desired

    • k-os warp: k-th order statistic loss. warp的一个变种

  • learning_rate: 初始学习率

  • item_alpha: L2 penalty on item features, 默认为0.0, 即不使用正则化. 开启正则化会降低训练的速度.

    • 使用时需检查最后输出的embedding weights是否都近似于0, 如果是说明这个值设定的太大了

  • user_alpha: L2 penalty on user features, 默认为0.0, 关闭

  • max_sampled: maximum number of negative samples used during WARP fitting.

  • random_state

然后是调用训练方法fit需要注意的参数:

  • interactions: np.float32 coo_matrix of shape [n_users, n_items]

    • 交互稀疏矩阵. 如果只有行为, 矩阵内的非0处值都为1; 如果是评分系统, 非0处的值为任意数值.

  • user_features: np.float32 csr_matrix of shape [n_users, n_user_features], optional

    • 每行代表一个user, 行中的每个值代表这个user对于每个用户特征的权值

  • item_features: np.float32 csr_matrix of shape [n_items, n_item_features], optional

  • sample_weight: np.float32 coo_matrix of shape [n_users, n_items], optional

  • epochs: 训练的epoch次数

  • num_threads

  • verbose: bool, optional, 默认为False

训练好之后的权值可以通过以下四个属性得到:

  • item_embeddings: np.float32 array of shape [n_item_features, n_components]

  • user_embeddings: np.float32 array of shape [n_user_features, n_components]

  • item_biases: np.float32 array of shape [n_item_features,]

  • user_biases: np.float32 array of shape [n_user_features,]

通常来说, warp

查看item对应的embedding:

或者使用weights来训练模型:

除了使用fit方法训练之外, 还可以使用fit_partial方法增量训练. 常用于多epoch训练的情景. fit_partial方法与fit方法传入的参数相同, 因为在fit方法中本身就调用了fit_partial方法.

预测结果

使用模型的predict方法对指定的user-item对进行预测(交互概率或预计评分). 需要特别注意数据的形式与转换过程.

  • user_ids: integer or np.int32 array of shape [n_pairs,]

    • 需要注意这里传入的是整数形式的user, 即模型中对user的编号, 而不是原始的user

  • item_ids: np.int32 array of shape [n_pairs,]

    • 同理, 也是item对应的整数索引

  • user_features: np.float32 csr_matrix of shape [n_users, n_user_features], optional

  • item_features: np.float32 csr_matrix of shape [n_items, n_item_features], optional

  • num_threads

返回的形式为:

  • np.float32 array of shape [n_pairs,]

    • Numpy array containing the recommendation scores for pairs defined by the inputs

这里使用lightfm.datasets中的fetch_movielens函数获取数据, 原因是将数据分成了train和test, 即训练集和验证集. 注意这里的训练集与验证集是按行为划分的, 并不是按照user划分的.

当然也可以使用Dataset手动生成train和test. 生成的方法为:

  • 首先使用sklearn中的train_test_split函数将行为数据打乱后按比例划分成train和test

  • 然后分别使用Dataset中的build_interactions方法生成行为稀疏矩阵

得到用于评测的test样本中的数值

对相应的item进行评估:

整体还是比较接近的.

不清楚为什么数值前面有个负号, 猜测是为了使用np.argsort排序方便

预测时, 传入的user与item需满足以下的关系:

  • 因为预测的是user-item对, 因此两者的输入长度应相等

  • 如果是预测一个一个user对多个item或一个item对多个user, 一个的那项只需要传入一个整数标量

评估方法

lightFM还提供了便捷的用于评价拟合好的模型优劣性的方法.

两个指标的意义分别为:

  • auc_score: Measure the ROC AUC metric for a model

    • the probability that a randomly chosen positive example has a higher score than a randomly chosen negative example

  • precision_at_k: Measure the precision at k metric for a model

    • the fraction of known positives in the first k positions of the ranked list of results. A perfect score is 1.0

其中precision_at_k方法配合warp损失函数, auc_score配合bpr损失函数使用更符合逻辑, 能取得更好的效果.

两个评价函数接收的参数形式是相同的:

  • model: LightFM模型, 已经训练好的

  • test_interactions: np.float32 csr_matrix of shape [n_users, n_items]

    • Non-zero entries representing known positives in the evaluation set

  • train_interactions: np.float32 csr_matrix of shape [n_users, n_items], optional

    • Non-zero entries representing known positives in the train set

    • These will be omitted from the score calculations to avoid re-recommending known positives

  • k: topK

  • user_features: np.float32 csr_matrix of shape [n_users, n_user_features], optional

  • item_features: np.float32 csr_matrix of shape [n_items, n_item_features], optional

  • num_threads

返回的是每个user计算得到的auc的值, 因此整体的需要进行平均:

最后更新于

这有帮助吗?