最后更新于
最后更新于
使用经典的数据集作为推荐的例子. 在lightFM中, 可以直接调用函数获取整理成稀疏矩阵格式的数据:
但在这里, 我们将从原始的数据开始, 记录从原始数据到可供lightFM模型使用的数据, 即稀疏矩阵形式(coo, csr). 从而将数据处理的方法直接使用在各种推荐数据集上.
下载好的数据集目录中包含很多文件, 其中的u.data
包含了所有数据. 文件中每一行为一个交互样本, 格式为user id | item id | rating | timestamp
, 列之间以tab
符分隔. 使用pandas
读取数据.
共有100000条行为数据.
lightFM模型中个各种方法只接受稀疏矩阵的形式, 因此需要把这种行形式的行为数据转换为(user, item)
这种稀疏矩阵的形式. 固然可以使用scipy
中的方法创建可以空的系数矩阵, 然后循环行为样本, 将对应位置填值, 但lightFM中提供了包装好的类来进行处理.
而且由于lightFM中使用user
和item
的特征, 使得整体数据情况比较复杂. 通过lightFM中的Dataset
类就能够很好地进行管理. lightfm.data.Dataset
能够做到:
user
和item
自身与整数索引之间的映射关系
user
和item
特征的管理, 包括特征的顺序等
生成(user, item)
对的稀疏矩阵
生成user
或item
的特征数据结构
首先创建一个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
特征.
如果没有任何user
和item
特征, 则这两个参数必须指定为True
. 每个user
, 每个item
都是一个独特的特征, 只会被该user
或item
使用到, 其他的不会使用. 在这种情况下, lightFM算法也就等价于普通的FM
算法.
在初始化完毕之后, 接下来需要将user列表和item列表为模型指定, 这一步需要调用Dataset
的fit
方法. 需要注意这里的fit
方法投入的不是行为数据, 只是所有user
和item
分别组成的列表.
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
的名称列表
这一步的作用是对每个user
和item
指定一个整数ID, 这个id就是传入列表中元素的顺序. ID从0开始, 在lightFM中使用的这种整数索引, 而不是原始的user
, item
名称.
然后就可以通过函数看到user
和item
的交互矩阵的大小了.
共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
的值, 因此整体的需要进行平均: