Author: C3P00

  • 深度解析NPA:基于个性化注意力的神经新闻推荐模型

    在当今信息爆炸的时代,如何从海量新闻中为用户精准推荐感兴趣的内容,是一个重要而富有挑战性的问题。本文将为您详细介绍一种先进的新闻推荐模型 – NPA(Neural News Recommendation with Personalized Attention),即基于个性化注意力的神经新闻推荐模型。

    NPA模型概述

    NPA模型是一种基于内容的新闻推荐方法,由微软研究院于2019年提出。其核心思想是通过深度学习技术,同时建模新闻内容和用户兴趣,并引入个性化注意力机制来捕捉不同用户的兴趣差异。

    NPA模型的主要特点包括:

    1. 使用CNN网络学习新闻的表示
    2. 基于用户点击历史学习用户兴趣表示
    3. 引入词级别的个性化注意力,关注不同用户的重要词
    4. 引入新闻级别的个性化注意力,关注用户历史中的重要新闻

    下面我们将深入剖析NPA模型的各个组成部分。

    新闻表示模块

    新闻表示模块的目标是将新闻内容转化为低维稠密向量。NPA模型主要利用新闻标题来学习新闻表示,具体步骤如下:

    1. 对新闻标题进行分词,并将每个词映射到预训练的词向量(如GloVe)
    2. 使用CNN网络对词向量序列进行卷积,提取局部语义特征
    3. 通过池化操作得到固定维度的新闻向量表示

    CNN的使用使得模型能够捕捉词序信息和短语级别的语义。相比RNN,CNN的并行性更好,训练速度更快。

    用户表示模块

    用户表示模块的目标是基于用户的历史行为,学习用户的兴趣表示。NPA模型的做法是:

    1. 获取用户近期点击的N篇新闻
    2. 使用新闻表示模块得到这N篇新闻的向量表示
    3. 通过注意力机制对这N个新闻向量进行加权平均,得到用户向量

    注意力机制的引入使得模型能够区分不同历史新闻的重要性,从而更精准地刻画用户兴趣。

    个性化注意力机制

    NPA模型的一大创新是引入了两级个性化注意力机制:

    词级别个性化注意力

    在新闻表示模块中,对新闻标题的每个词赋予不同的注意力权重。关键是这个注意力权重不仅与词本身有关,还与用户向量相关。具体计算公式如下:

    $$a_i = softmax(v^T tanh(W_1 e_i + W_2 u))$$

    其中$e_i$是第i个词的词向量,$u$是用户向量,$W_1,W_2,v$是可学习的参数。

    这样不同用户对同一篇新闻的同一个词会有不同的注意力分配,体现了个性化。

    新闻级别个性化注意力

    在用户表示模块中,对用户历史点击的每篇新闻赋予不同的注意力权重。同样地,这个权重也是个性化的:

    $$\beta_j = softmax(v’^T tanh(W_3 d_j + W_4 u))$$

    其中$d_j$是第j篇新闻的向量表示,$u$是用户向量,$W_3,W_4,v’$是可学习的参数。

    通过这两级注意力机制,NPA模型能够更好地捕捉用户的个性化兴趣。

    模型训练

    NPA模型采用负采样的方式进行训练。对于每个正样本(用户点击的新闻),随机采样若干负样本(用户未点击的新闻)。模型的目标是最大化正样本的预测概率,同时最小化负样本的预测概率。

    损失函数采用交叉熵:

    $$L = -\frac{1}{N}\sum_{(u,d^+,d^-)\in \mathcal{S}} log(\sigma(\hat{y}{u,d^+})) + \sum{d^-\in\mathcal{D}^-}log(1-\sigma(\hat{y}_{u,d^-}))$$

    其中$\hat{y}_{u,d}$是模型对用户$u$和新闻$d$的匹配度预测。

    实验结果

    研究者在MIND数据集上进行了大量实验,验证了NPA模型的有效性。主要结果包括:

    1. NPA模型在各项评价指标上均优于传统的协同过滤、矩阵分解等方法
    2. 个性化注意力机制带来了显著的性能提升
    3. NPA模型能够很好地处理冷启动问题

    下面是在MIND-demo数据集上的部分实验结果:

    {'group_auc': 0.6005, 'mean_mrr': 0.2711, 'ndcg@5': 0.2936, 'ndcg@10': 0.3586}

    总结与展望

    NPA模型通过深度学习和个性化注意力机制,有效地解决了新闻推荐中的关键问题。其主要优势包括:

    1. 端到端的训练方式,无需人工特征工程
    2. 个性化注意力机制,能够捕捉用户兴趣的细微差异
    3. 基于内容的方法,可以很好地处理新闻的冷启动问题

    未来的研究方向可能包括:

    1. 引入更多的新闻特征,如图片、视频等多模态信息
    2. 探索如何建模用户长期和短期兴趣
    3. 结合知识图谱,提高推荐的可解释性

    总的来说,NPA模型为个性化新闻推荐提供了一个强大而灵活的框架,具有广阔的应用前景。

    参考文献

    1. Wu, C., Wu, F., An, M., Huang, J., Huang, Y., & Xie, X. (2019). Neural news recommendation with attentive multi-view learning. IJCAI.
    2. Wang, H., Zhang, F., Xie, X., & Guo, M. (2018). DKN: Deep knowledge-aware network for news recommendation. In Proceedings of the 2018 world wide web conference.
    3. Wu, C., Wu, F., Ge, S., Qi, T., Huang, Y., &
  • NCF:基于神经网络的协同过滤算法

    引言

    神经网络协同过滤 (NCF) 是一种将矩阵分解与多层感知机相结合的推荐算法,能够有效地学习用户和物品之间的复杂交互关系。本篇文章将以 ncf_movielens.ipynb 示例为例,详细介绍如何使用 Recommenders 工具包实现 NCF 算法,并对模型性能进行评估。

    数据准备

    本示例使用经典的 MovieLens 数据集,该数据集包含了用户对电影的评分信息。首先,使用 recommenders.datasets.movielens 模块加载数据集,并指定使用的数据集大小和数据格式。

    df = movielens.load_pandas_df(
        size=MOVIELENS_DATA_SIZE,
        header=["userID", "itemID", "rating", "timestamp"]
    )

    接下来,使用 python_chrono_split 函数按照时间顺序将数据集划分为训练集和测试集,划分比例为 75:25。

    train, test = python_chrono_split(df, 0.75)

    为了避免冷启动问题,将测试集中未出现在训练集中的用户和物品过滤掉。

    test = test[test["userID"].isin(train["userID"].unique())]
    test = test[test["itemID"].isin(train["itemID"].unique())]

    模型构建

    使用 recommenders.models.ncf.ncf_singlenode 模块中的 NCF 类构建 NCF 模型。

    model = NCF (
        n_users=data.n_users,
        n_items=data.n_items,
        model_type="NeuMF",
        n_factors=4,
        layer_sizes=[16,8,4],
        n_epochs=EPOCHS,
        batch_size=BATCH_SIZE,
        learning_rate=1e-3,
        verbose=10,
        seed=SEED
    )

    在 NCF 模型中,model_type 参数指定使用的模型类型,本示例使用 NeuMF 模型,该模型结合了广义矩阵分解 (GMF) 和多层感知机 (MLP) 的优势。n_factors 参数表示隐含特征维度,layer_sizes 参数指定 MLP 网络的层数和每层的神经元数量。

    模型训练

    使用训练集对 NCF 模型进行训练。

    with Timer() as train_time:
        model.fit(data)
    
    print("Took {} seconds for training.".format(train_time))

    生成推荐结果

    在电影推荐场景中,通常不推荐用户已经看过的电影。因此,需要将训练集中出现过的用户-电影组合从推荐结果中剔除。

    with Timer() as test_time:
        users, items, preds = [], [], []
        item = list(train.itemID.unique())
        for user in train.userID.unique():
            user = [user] * len(item)
            users.extend(user)
            items.extend(item)
            preds.extend(list(model.predict(user, item, is_list=True)))
    
        all_predictions = pd.DataFrame(data={"userID": users, "itemID":items, "prediction":preds})
    
        merged = pd.merge(train, all_predictions, on=["userID", "itemID"], how="outer")
        all_predictions = merged[merged.rating.isnull()].drop('rating', axis=1)
    
    print("Took {} seconds for prediction.".format(test_time))

    模型评估

    使用 recommenders.evaluation.python_evaluation 模块中的评估指标对模型进行评估。

    eval_map = map(test, all_predictions, col_prediction='prediction', k=TOP_K)
    eval_ndcg = ndcg_at_k(test, all_predictions, col_prediction='prediction', k=TOP_K)
    eval_precision = precision_at_k(test, all_predictions, col_prediction='prediction', k=TOP_K)
    eval_recall = recall_at_k(test, all_predictions, col_prediction='prediction', k=TOP_K)
    
    print("MAP:\t%f" % eval_map,
          "NDCG:\t%f" % eval_ndcg,
          "Precision@K:\t%f" % eval_precision,
          "Recall@K:\t%f" % eval_recall, sep='\n')

    总结

    本篇文章以 ncf_movielens.ipynb 为例,详细介绍了如何使用 Recommenders 工具包实现 NCF 算法,并对模型性能进行了评估。NCF 算法能够有效地学习用户和物品之间的复杂交互关系,在推荐系统中具有广泛的应用。

  • NAML:基于注意力机制的多视角新闻推荐算法

    引言

    在信息过载的时代,个性化新闻推荐显得尤为重要。为了更精准地捕捉用户的兴趣,NAML 算法利用多视角学习,从新闻标题、正文、类别和子类别等多个角度学习新闻表示,并结合用户历史行为学习用户表示,从而实现更精准的新闻推荐。

    NAML 算法原理

    NAML 算法的核心思想是利用注意力机制,从多视角学习新闻表示和用户表示,并根据两者之间的匹配程度预测用户点击新闻的概率。具体来说,NAML 算法包含以下几个步骤:

    1. 新闻编码器:
      • 标题编码器: 使用卷积神经网络 (CNN) 对新闻标题进行编码,得到新闻标题的语义表示向量。
      • 正文编码器: 使用 CNN 对新闻正文进行编码,得到新闻正文的语义表示向量。
      • 类别编码器: 使用嵌入向量表示新闻的类别。
      • 子类别编码器: 使用嵌入向量表示新闻的子类别。
      • 注意力网络: 使用注意力网络对上述四个向量进行加权平均,得到最终的新闻表示向量。
    2. 用户编码器: 使用 GRU 网络对用户浏览过的新闻进行编码,得到用户的兴趣表示向量。
    3. 注意力机制: 使用加性注意力机制分别对新闻表示向量和用户表示向量进行加权,选择重要的词语和新闻,学习更具信息量的新闻表示和用户表示。
    4. 点击率预测: 将新闻表示向量和用户表示向量输入到一个全连接神经网络中,预测用户点击该新闻的概率。

    MIND 数据集

    MIND 数据集是一个大规模英文新闻数据集,包含了 1,000,000 用户、161,013 篇新闻文章和 15,777,377 条点击日志。每篇新闻文章包含丰富的文本内容,包括标题、摘要、正文、类别和实体。每条点击日志包含用户的点击事件、未点击事件以及该用户在该次点击之前的历史点击行为。

    本示例使用 MIND 数据集的子集 MIND demo,包含 5,000 用户、9,432 篇新闻文章和 6,134 条点击日志。由于 MIND 数据集没有发布新闻正文,本示例使用新闻摘要代替正文。

    NAML 模型训练

    首先,需要下载 MIND demo 数据集和预训练的 GloVe 词嵌入文件。

    tmpdir = TemporaryDirectory()
    data_path = tmpdir.name
    
    # ... 定义数据文件路径 ...
    
    mind_url, mind_train_dataset, mind_dev_dataset, mind_utils = get_mind_data_set(MIND_type)
    
    if not os.path.exists(train_news_file):
        download_deeprec_resources(mind_url, os.path.join(data_path, 'train'), mind_train_dataset)
    
    # ... 下载验证集和词嵌入文件 ...

    然后,设置模型超参数,并创建 NAML 模型。

    # 设置超参数
    epochs = 5
    seed = 42
    batch_size = 32
    
    # ...
    
    # 创建 NAML 模型
    hparams = prepare_hparams(yaml_file,
                              wordEmb_file=wordEmb_file,
                              wordDict_file=wordDict_file,
                              userDict_file=userDict_file,
                              vertDict_file=vertDict_file,
                              subvertDict_file=subvertDict_file,
                              batch_size=batch_size,
                              epochs=epochs)
    
    iterator = MINDAllIterator
    model = NAMLModel(hparams, iterator, seed=seed)

    最后,使用训练集和验证集对模型进行训练。

    model.fit(train_news_file, train_behaviors_file, valid_news_file, valid_behaviors_file)

    模型评估

    模型训练完成后,可以使用验证集对模型性能进行评估。

    res_syn = model.run_eval(valid_news_file, valid_behaviors_file)
    print(res_syn)

    评估指标包括 Group AUC、Mean MRR、NDCG@5 和 NDCG@10。

    模型保存

    训练完成后,可以使用 save_weights 方法保存模型参数。

    model_path = os.path.join(data_path, "model")
    os.makedirs(model_path, exist_ok=True)
    
    model.model.save_weights(os.path.join(model_path, "naml_ckpt"))

    总结

    NAML 算法是一种基于注意力机制的多视角新闻推荐算法,能够有效学习新闻的多方面特征和用户的兴趣,从而提升推荐效果。微软 Recommenders 工具提供了 NAML 算法的示例代码,方便用户快速上手并进行实验。

  • LSTUR:兼顾长期和短期兴趣的新闻推荐算法

    引言

    在新闻推荐领域,准确捕捉用户的兴趣至关重要。用户的兴趣可以分为长期兴趣和短期兴趣两类。长期兴趣指的是用户长期以来稳定的偏好,而短期兴趣则指的是用户在短期内表现出的兴趣变化。LSTUR 算法结合了用户的长期兴趣和短期兴趣,能够更精准地为用户推荐新闻。

    LSTUR 算法原理

    LSTUR 算法的核心思想是分别学习用户的长期表示和短期表示,并将两者融合,得到最终的用户表示。具体来说,LSTUR 算法包含以下几个步骤:

    1. 新闻编码器: 使用卷积神经网络 (CNN) 对新闻标题进行编码,得到新闻的语义表示向量。
    2. 用户编码器:
      • 长期表示: 使用用户 ID 的嵌入向量表示用户的长期兴趣。
      • 短期表示: 使用门控循环单元 (GRU) 网络对用户最近浏览过的新闻进行编码,得到用户的短期兴趣表示向量。
    3. 长期和短期表示融合: 将用户的长期表示和短期表示融合,得到最终的用户表示向量。LSTUR 算法提供了两种融合方法:
      • 使用长期表示初始化 GRU 网络的隐藏状态。
      • 将长期表示和短期表示拼接成一个统一的用户向量。
    4. 点击率预测: 将新闻表示向量和用户表示向量输入到一个全连接神经网络中,预测用户点击该新闻的概率。

    MIND 数据集

    MIND 数据集是一个大规模英文新闻数据集,包含了 1,000,000 用户、161,013 篇新闻文章和 15,777,377 条点击日志。每篇新闻文章包含丰富的文本内容,包括标题、摘要、正文、类别和实体。每条点击日志包含用户的点击事件、未点击事件以及该用户在该次点击之前的历史点击行为。

    本示例使用 MIND 数据集的子集 MIND demo,包含 5,000 用户、9,432 篇新闻文章和 6,134 条点击日志。

    LSTUR 模型训练

    首先,需要下载 MIND demo 数据集和预训练的 GloVe 词嵌入文件。

    tmpdir = TemporaryDirectory()
    data_path = tmpdir.name
    
    # ... 定义数据文件路径 ...
    
    mind_url, mind_train_dataset, mind_dev_dataset, mind_utils = get_mind_data_set(MIND_type)
    
    if not os.path.exists(train_news_file):
        download_deeprec_resources(mind_url, os.path.join(data_path, 'train'), mind_train_dataset)
    
    # ... 下载验证集和词嵌入文件 ...

    然后,设置模型超参数,并创建 LSTUR 模型。

    # 设置超参数
    epochs = 5
    seed = 40
    batch_size = 32
    
    # ...
    
    # 创建 LSTUR 模型
    hparams = prepare_hparams(yaml_file,
                              wordEmb_file=wordEmb_file,
                              wordDict_file=wordDict_file,
                              userDict_file=userDict_file,
                              batch_size=batch_size,
                              epochs=epochs)
    
    iterator = MINDIterator
    model = LSTURModel(hparams, iterator, seed=seed)

    最后,使用训练集和验证集对模型进行训练。

    model.fit(train_news_file, train_behaviors_file, valid_news_file, valid_behaviors_file)

    模型评估

    模型训练完成后,可以使用验证集对模型性能进行评估。

    res_syn = model.run_eval(valid_news_file, valid_behaviors_file)
    print(res_syn)

    评估指标包括 Group AUC、Mean MRR、NDCG@5 和 NDCG@10。

    模型保存

    训练完成后,可以使用 save_weights 方法保存模型参数。

    model_path = os.path.join(data_path, "model")
    os.makedirs(model_path, exist_ok=True)
    
    model.model.save_weights(os.path.join(model_path, "lstur_ckpt"))

    总结

    LSTUR 算法是一种兼顾用户长期兴趣和短期兴趣的新闻推荐算法,能够有效提升推荐效果。微软 Recommenders 工具提供了 LSTUR 算法的示例代码,方便用户快速上手并进行实验。

  • LightGBM:电商广告点击率预估利器

    引言

    在电商平台中,广告点击率 (CTR) 预估对于广告投放效果至关重要。准确预测用户点击广告的概率,可以帮助广告主优化广告投放策略,提升广告收益。LightGBM 作为一种高效的梯度提升决策树算法,在 CTR 预估任务中表现出色。本篇文章将以 lightgbm_tinycriteo.ipynb 示例为例,介绍如何使用 LightGBM 训练 CTR 预估模型,并探讨模型优化策略。

    LightGBM 简介

    LightGBM 是微软开源的一种梯度提升框架,它使用基于树的学习算法,并针对分布式计算和高效率进行了优化。LightGBM 具有以下优势:

    • 训练速度快,效率高。
    • 内存占用低。
    • 预测精度高。
    • 支持并行计算和 GPU 加速。
    • 能够处理大规模数据。

    数据准备

    本示例使用 Criteo 数据集,该数据集是 CTR 预估领域的经典基准数据集。原始数据集包含 39 个特征,其中 13 个为数值特征 (I1-I13),26 个为类别特征 (C1-C26)。由于原始数据集规模较大,本示例使用了一个包含约 10 万个样本的子集。

    # 定义特征列和标签列
    nume_cols = ["I" + str(i) for i in range(1, 14)]
    cate_cols = ["C" + str(i) for i in range(1, 27)]
    label_col = "Label"
    
    # 加载数据集
    header = [label_col] + nume_cols + cate_cols
    with TemporaryDirectory() as tmp:
        all_data = criteo.load_pandas_df(size=SIZE, local_cache_path=tmp, header=header)

    将数据集按照时间顺序划分为训练集、验证集和测试集,划分比例为 8:1:1。

    # 划分数据集
    length = len(all_data)
    train_data = all_data.loc[:0.8*length-1]
    valid_data = all_data.loc[0.8*length:0.9*length-1]
    test_data = all_data.loc[0.9*length:]

    模型训练与评估

    基础用法

    对于 LightGBM 的基础用法,只需对类别特征进行简单的顺序编码即可。

    # 顺序编码
    ord_encoder = ce.ordinal.OrdinalEncoder(cols=cate_cols)
    
    # 编码数据
    train_x, train_y = encode_csv(train_data, ord_encoder, label_col)
    valid_x, valid_y = encode_csv(valid_data, ord_encoder, label_col, "transform")
    test_x, test_y = encode_csv(test_data, ord_encoder, label_col, "transform")

    创建 LightGBM 数据集,并设置模型参数。

    # 创建 LightGBM 数据集
    lgb_train = lgb.Dataset(train_x, train_y.reshape(-1), params=params, categorical_feature=cate_cols)
    lgb_valid = lgb.Dataset(valid_x, valid_y.reshape(-1), reference=lgb_train, categorical_feature=cate_cols)
    lgb_test = lgb.Dataset(test_x, test_y.reshape(-1), reference=lgb_train, categorical_feature=cate_cols)
    
    # 训练模型
    lgb_model = lgb.train(params,
                          lgb_train,
                          num_boost_round=NUM_OF_TREES,
                          valid_sets=lgb_valid,
                          categorical_feature=cate_cols,
                          callbacks=[lgb.early_stopping(EARLY_STOPPING_ROUNDS)])
    
    # 预测测试集结果
    test_preds = lgb_model.predict(test_x)
    
    # 计算 AUC 和 Logloss
    auc = roc_auc_score(np.asarray(test_y.reshape(-1)), np.asarray(test_preds))
    logloss = log_loss(np.asarray(test_y.reshape(-1)), np.asarray(test_preds))
    
    print({"auc": auc, "logloss": logloss})

    优化用法

    为了进一步提升模型性能,可以对类别特征进行标签编码和二进制编码,并将数值特征的缺失值填充为均值。

    # 标签编码和二进制编码
    num_encoder = lgb_utils.NumEncoder(cate_cols, nume_cols, label_col)
    train_x, train_y = num_encoder.fit_transform(train_data)
    valid_x, valid_y = num_encoder.transform(valid_data)
    test_x, test_y = num_encoder.transform(test_data)
    
    # 训练模型
    # ...
    
    # 预测测试集结果
    test_preds = lgb_model.predict(test_x)
    
    # 计算 AUC 和 Logloss
    auc = roc_auc_score(np.asarray(test_y.reshape(-1)), np.asarray(test_preds))
    logloss = log_loss(np.asarray(test_y.reshape(-1)), np.asarray(test_preds))
    
    print({"auc": auc, "logloss": logloss})

    模型保存与加载

    训练完成后,可以使用 save_model 方法保存模型,并使用 Booster 类加载模型。

    # 保存模型
    with TemporaryDirectory() as tmp:
        save_file = os.path.join(tmp, "finished.model")
        lgb_model.save_model(save_file)
        loaded_model = lgb.Booster(model_file=save_file)
    
    # 使用加载的模型进行预测
    test_preds = loaded_model.predict(test_x)

    总结

    LightGBM 是一种高效的梯度提升决策树算法,在 CTR 预估任务中表现出色。通过对类别特征进行编码和缺失值填充等优化策略,可以进一步提升模型性能。

  • GeoIMC:融合几何信息的电影推荐算法

    引言

    推荐系统领域中,矩阵分解技术是协同过滤算法的重要分支。传统的矩阵分解方法通常只考虑用户和物品之间的交互信息,而忽略了用户和物品本身的特征。GeoIMC 算法将用户和物品的特征信息融入到矩阵分解过程中,并利用黎曼优化方法求解模型参数,从而提升推荐效果。

    GeoIMC 算法原理

    GeoIMC 算法基于 Jawanpuria 等人 (2019) 的研究成果,将用户和物品的特征信息融入到矩阵分解过程中。以 MovieLens-100K (ML100K) 数据集为例,假设 $X \in R^{m \times d_1}$ 和 $Z \in R^{n \times d_2}$ 分别表示用户和电影的特征矩阵,$M \in R^{m \times n}$ 表示用户对电影的评分矩阵。GeoIMC 算法将评分矩阵建模为 $M = XUBV^TZ^T$,其中 $U \in R^{d_1 \times k}$、$V \in R^{d_2 \times k}$ 和 $B \in R^{k \times k}$ 分别为正交矩阵、正交矩阵和对称正定矩阵。模型参数通过 Pymanopt 工具包进行黎曼优化求解。

    数据准备

    本示例使用 MovieLens 100K 数据集,并使用与 Xin Dong 等人 (2017) 相同的方法生成用户和电影的特征向量。

    # 创建临时目录下载 ML100K 数据集
    dp = tempfile.mkdtemp(suffix='-geoimc')
    movielens.download_movielens(MOVIELENS_DATA_SIZE, f"{dp}/ml-100k.zip")
    with zipfile.ZipFile(f"{dp}/ml-100k.zip", 'r') as z:
        z.extractall(dp)
    
    # 加载数据集和特征
    dataset = ML_100K(
        normalize=normalize,
        target_transform='binarize'
    )
    dataset.load_data(f"{dp}/ml-100k/")

    模型训练

    使用 IMCProblem 类初始化 GeoIMC 问题,并设置正则化参数和模型秩。

    np.random.seed(10)
    prblm = IMCProblem(
        dataset.training_data,
        lambda1=regularizer,
        rank=rank
    )
    
    # 求解优化问题
    prblm.solve(
        max_time,
        max_iters,
        verbosity
    )

    生成推荐结果

    使用 Inferer 类初始化推理器,并使用训练得到的模型参数预测用户对电影的评分。

    # 初始化推理器
    inferer = Inferer(
        method='dot'
    )
    
    # 预测评分
    predictions = inferer.infer(
        dataset.test_data,
        prblm.W
    )

    模型评估

    使用 rmsemae 函数计算模型的均方根误差 (RMSE) 和平均绝对误差 (MAE)。

    # 准备测试集和预测结果数据框
    user_ids = dataset.test_data.get_data().tocoo().row
    item_ids = dataset.test_data.get_data().tocoo().col
    test_df = pd.DataFrame(
        data={
            "userID": user_ids,
            "itemID": item_ids,
            "rating": dataset.test_data.get_data().data
        }
    )
    predictions_df = pd.DataFrame(
        data={
            "userID": user_ids,
            "itemID": item_ids,
            "prediction": [predictions[uid, iid] for uid, iid in list(zip(user_ids, item_ids))]
        }
    )
    
    # 计算 RMSE 和 MAE
    RMSE = rmse(
        test_df,
        predictions_df
    )
    MAE = mae(
        test_df,
        predictions_df
    )
    
    print(f"""
    RMSE: {RMSE}
    MAE: {MAE}
    """)

    总结

    GeoIMC 算法通过将用户和物品的特征信息融入到矩阵分解过程中,并利用黎曼优化方法求解模型参数,能够有效提升推荐效果。本示例展示了如何使用 Recommenders 工具包实现 GeoIMC 算法,并对模型性能进行了评估。

    参考文献

    [1] Pratik Jawanpuria, Arjun Balgovind, Anoop Kunchukuttan, Bamdev Mishra. Learning Multilingual Word Embeddings in Latent Metric Space: A Geometric Approach. Transaction of the Association for Computational Linguistics (TACL), Volume 7, p.107-120, 2019.

    [2] Xin Dong, Lei Yu, Zhonghuo Wu, Yuxia Sun, Lingfeng Yuan, Fangxi Zhang. A Hybrid Collaborative Filtering Model withDeep Structure for Recommender Systems.
    Proceedings of the Thirty-First AAAI Conference on Artificial Intelligence (AAAI-17), p.1309-1315, 2017.

  • FastAI:快速构建电影推荐系统

    引言

    FastAI 作为一个易于使用且功能强大的深度学习库,为推荐系统的构建提供了便捷的工具。本篇文章将以 fastai_movielens.ipynb 示例为例,介绍如何利用 FastAI 框架,快速构建一个基于协同过滤的电影推荐系统,并对模型性能进行评估。

    数据准备

    本示例使用经典的 MovieLens 数据集,该数据集包含用户对电影的评分信息。首先,使用 recommenders.datasets.movielens 模块加载数据集,并确保用户 ID 和电影 ID 以字符串类型加载,避免与嵌入 ID 混淆。

    ratings_df = movielens.load_pandas_df(
        size=MOVIELENS_DATA_SIZE,
        header=[USER,ITEM,RATING,TIMESTAMP]
    )
    
    # 确保 ID 以字符串类型加载
    ratings_df[USER] = ratings_df[USER].astype('str')
    ratings_df[ITEM] = ratings_df[ITEM].astype('str')

    接下来,使用 python_stratified_split 函数将数据集划分为训练集/验证集和测试集,划分比例为 75:25。

    train_valid_df, test_df = python_stratified_split(
        ratings_df,
        ratio=0.75,
        min_rating=1,
        filter_by="item",
        col_user=USER,
        col_item=ITEM
    )
    
    # 从测试集中移除“冷启动”用户
    test_df = test_df[test_df.userID.isin(train_valid_df.userID)]

    模型训练

    FastAI 提供了 collab_learner 函数,用于快速构建协同过滤模型。默认情况下,collab_learner 使用 EmbeddingDotBias 模型,该模型为用户和电影创建嵌入向量,并将它们映射到指定维度的浮点数空间。

    # 设置随机种子以确保结果可复现
    np.random.seed(101)
    torch.manual_seed(101)
    torch.cuda.manual_seed_all(101)
    
    # 创建 CollabDataLoaders
    data = CollabDataLoaders.from_df(train_valid_df,
                                         user_name=USER,
                                         item_name=ITEM,
                                         rating_name=RATING,
                                         valid_pct=0)
    
    # 创建 collab_learner
    learn = collab_learner(data, n_factors=N_FACTORS, y_range=[0,5.5], wd=1e-1)

    collab_learner 中,n_factors 参数表示隐含特征维度,y_range 参数设置评分范围,wd 参数设置权重衰减以进行正则化。

    使用 fit_one_cycle 函数训练模型,并设置学习率和迭代次数。

    with Timer() as train_time:
        learn.fit_one_cycle(EPOCHS, lr_max=5e-3)

    生成推荐结果

    为了生成推荐结果,首先需要获取模型已知的所有用户和电影,以及测试集中的用户。

    # 获取所有用户和电影
    total_users, total_items = learner.dls.classes.values()
    total_items = total_items[1:]
    total_users = total_users[1:]
    
    # 获取测试集中的用户
    test_users = test_df[USER].unique()
    test_users = np.intersect1d(test_users, total_users)

    然后,构建测试集用户和所有已知电影的笛卡尔积,并移除训练集中出现过的用户-电影组合。

    # 构建笛卡尔积
    users_items = cartesian_product(np.array(test_users),np.array(total_items))
    users_items = pd.DataFrame(users_items, columns=[USER,ITEM])
    
    # 移除训练集中出现过的组合
    training_removed = pd.merge(users_items, train_valid_df.astype(str), on=[USER, ITEM], how='left')
    training_removed = training_removed[training_removed[RATING].isna()][[USER, ITEM]]

    最后,使用 score 函数对模型进行评分,并获取 Top-K 推荐结果。

    with Timer() as test_time:
        top_k_scores = score(learner,
                             test_df=training_removed,
                             user_col=USER,
                             item_col=ITEM,
                             prediction_col=PREDICTION)

    模型评估

    使用 recommenders.evaluation.python_evaluation 模块中的评估指标对模型进行评估。

    # 排序指标评估
    eval_map = map(test_df, top_k_scores, col_user=USER, col_item=ITEM,
                   col_rating=RATING, col_prediction=PREDICTION,
                   relevancy_method="top_k", k=TOP_K)
    
    eval_ndcg = ndcg_at_k(test_df, top_k_scores, col_user=USER, col_item=ITEM,
                          col_rating=RATING, col_prediction=PREDICTION,
                          relevancy_method="top_k", k=TOP_K)
    
    # ... 其他排序指标评估 ...
    
    # 评分预测指标评估
    eval_rmse = rmse(test_df, scores, col_user=USER, col_item=ITEM, col_rating=RATING, col_prediction=PREDICTION)
    eval_mae = mae(test_df, scores, col_user=USER, col_item=ITEM, col_rating=RATING, col_prediction=PREDICTION)
    
    # ... 其他评分预测指标评估 ...
    
    # 打印评估指标
    print(f"Model:\t\t{learn.__class__.__name__}\n"
          f"Top K:\t\t{TOP_K}\n"
          f"MAP:\t\t{eval_map:.6f}\n"
          f"NDCG:\t\t{eval_ndcg:.6f}\n"
          # ... 打印其他排序指标 ...
          f"RMSE:\t\t\t{eval_rmse:.6f}\n"
          f"MAE:\t\t\t{eval_mae:.6f}\n"
          # ... 打印其他评分预测指标 ...
         )

    总结

    本篇文章以 fastai_movielens.ipynb 为例,介绍了如何使用 FastAI 快速构建一个基于协同过滤的电影推荐系统。FastAI 提供了简洁的接口和高效的训练方法,使得构建推荐系统变得更加容易。

  • 深度知识感知网络:DKN 新闻推荐算法解析

    引言

    在信息爆炸的时代,如何从海量新闻中为用户推荐感兴趣的内容,成为了推荐系统研究的热点之一。传统的基于 ID 的协同过滤算法往往难以捕捉新闻内容的语义信息,而基于内容的推荐算法则需要人工提取新闻特征,效率低下。深度知识感知网络 (DKN) 算法应运而生,它结合了深度学习和知识图谱的优势,能够自动学习新闻内容的语义表示,并利用知识图谱中的实体信息提升推荐效果。

    DKN 算法原理

    DKN 算法的核心思想是将新闻内容和知识图谱信息融合到一个深度学习模型中,通过联合学习语义级和知识级的新闻表示,实现更精准的推荐。具体来说,DKN 算法主要包含以下几个步骤:

    1. 知识图谱表示学习: 使用 TransX 方法将知识图谱中的实体和关系嵌入到低维向量空间中,得到实体嵌入向量。
    2. 新闻语义表示学习: 使用卷积神经网络 (CNN) 对新闻标题进行编码,得到新闻语义嵌入向量。
    3. 知识感知卷积神经网络 (KCNN): 将实体嵌入向量和新闻语义嵌入向量融合,并使用 KCNN 进行特征提取,得到最终的新闻表示向量。
    4. 注意力机制: 使用注意力机制对用户的历史点击行为进行加权平均,得到用户的兴趣表示向量。
    5. 点击率预测: 将新闻表示向量和用户兴趣表示向量输入到一个全连接神经网络中,预测用户点击该新闻的概率。

    MIND 数据集

    MIND 数据集是一个大规模英文新闻数据集,包含了 1,000,000 用户、161,013 篇新闻文章和 15,777,377 条点击日志。每篇新闻文章包含丰富的文本内容,包括标题、摘要、正文、类别和实体。每条点击日志包含用户的点击事件、未点击事件以及该用户在该次点击之前的历史点击行为。

    本示例使用 MIND 数据集的子集 MIND demo,包含 500 用户、9,432 篇新闻文章和 6,134 条点击日志。

    DKN 模型训练

    首先,需要下载 MIND demo 数据集和预训练的词嵌入、实体嵌入和上下文嵌入文件。

    tmpdir = TemporaryDirectory()
    data_path = os.path.join(tmpdir.name, "mind-demo-dkn")
    
    # ... 定义数据文件路径 ...
    
    if not os.path.exists(yaml_file):
        download_deeprec_resources("https://recodatasets.z20.web.core.windows.net/deeprec/", tmpdir.name, "mind-demo-dkn.zip")

    然后,设置模型超参数,并创建 DKN 模型。

    # 设置超参数
    EPOCHS = 10
    HISTORY_SIZE = 50
    BATCH_SIZE = 500
    
    # 创建 DKN 模型
    hparams = prepare_hparams(yaml_file,
                              news_feature_file = news_feature_file,
                              user_history_file = user_history_file,
                              wordEmb_file=wordEmb_file,
                              entityEmb_file=entityEmb_file,
                              contextEmb_file=contextEmb_file,
                              epochs=EPOCHS,
                              history_size=HISTORY_SIZE,
                              batch_size=BATCH_SIZE)
    
    model = DKN(hparams, DKNTextIterator)

    最后,使用训练集和验证集对模型进行训练。

    model.fit(train_file, valid_file)

    模型评估

    模型训练完成后,可以使用测试集对模型性能进行评估。

    res = model.run_eval(test_file)
    print(res)

    评估指标包括 AUC、Group AUC、Mean MRR、NDCG@5 和 NDCG@10。

    总结

    DKN 算法是一种结合了深度学习和知识图谱的先进新闻推荐算法,能够有效提升推荐效果。微软 Recommenders 工具提供了 DKN 算法的示例代码,方便用户快速上手并进行实验。

  • 基于 PySpark 的电影推荐系统:深入解析 ALS 算法

    引言

    协同过滤算法是推荐系统中应用最广泛的算法之一,而交替最小二乘法 (ALS) 则是协同过滤算法中的一种经典算法。本篇文章将以微软 Recommenders 工具中的 als_movielens.ipynb 示例为例,详细介绍如何使用 PySpark 实现基于 ALS 算法的电影推荐系统,并对模型性能进行评估。

    数据准备

    本示例使用经典的 MovieLens 数据集,该数据集包含了用户对电影的评分信息。首先,需要使用 recommenders.datasets.movielens 模块加载数据集,并指定使用的数据集大小和数据格式。

    # 定义数据格式
    schema = StructType(
        (
            StructField(COL_USER, IntegerType()),
            StructField(COL_ITEM, IntegerType()),
            StructField(COL_RATING, FloatType()),
            StructField(COL_TIMESTAMP, LongType()),
        )
    )
    
    # 加载 MovieLens 100k 数据集
    data = movielens.load_spark_df(spark, size=MOVIELENS_DATA_SIZE, schema=schema)
    data.show()

    接下来,使用 spark_random_split 函数将数据集划分为训练集和测试集,划分比例为 75:25。

    train, test = spark_random_split(data, ratio=0.75, seed=123)

    模型构建

    使用 PySpark MLlib 中的 ALS 模块构建 ALS 模型。

    # 设置模型参数
    als = ALS(
        rank=10,
        maxIter=15,
        implicitPrefs=False,
        regParam=0.05,
        coldStartStrategy='drop',
        nonnegative=False,
        seed=42,
        **header
    )
    
    # 训练模型
    with Timer() as train_time:
        model = als.fit(train)

    在 ALS 模型中,rank 参数表示隐含特征维度,maxIter 参数表示最大迭代次数,regParam 参数表示正则化系数。

    生成推荐结果

    为了避免推荐用户已经评分过的电影,需要将训练集中出现过的用户-电影组合从推荐结果中剔除。

    with Timer() as test_time:
        # 生成所有用户-电影组合
        users = train.select(COL_USER).distinct()
        items = train.select(COL_ITEM).distinct()
        user_item = users.crossJoin(items)
    
        # 预测评分
        dfs_pred = model.transform(user_item)
    
        # 剔除训练集中出现过的用户-电影组合
        dfs_pred_exclude_train = dfs_pred.alias("pred").join(
            train.alias("train"),
            (dfs_pred[COL_USER] == train[COL_USER]) & (dfs_pred[COL_ITEM] == train[COL_ITEM]),
            how='outer'
        )
    
        # 获取最终推荐结果
        top_all = dfs_pred_exclude_train.filter(dfs_pred_exclude_train[f"train.{COL_RATING}"].isNull()) \
            .select('pred.' + COL_USER, 'pred.' + COL_ITEM, 'pred.' + "prediction")
    
        # 触发计算
        top_all.cache().count()

    模型评估

    使用 SparkRankingEvaluationSparkRatingEvaluation 模块对模型进行评估。

    # 排序指标评估
    rank_eval = SparkRankingEvaluation(test, top_all, k = TOP_K, col_user=COL_USER, col_item=COL_ITEM,
                                        col_rating=COL_RATING, col_prediction="prediction",
                                        relevancy_method="top_k")
    
    # 评分预测指标评估
    rating_eval = SparkRatingEvaluation(test, prediction, col_user=COL_USER, col_item=COL_ITEM,
                                        col_rating=COL_RATING, col_prediction="prediction")
    
    # 打印评估指标
    print(f"Model:\tALS\n"
          f"Top K:\t{rank_eval.k}\n"
          f"MAP:\t{rank_eval.map_at_k():.6f}\n"
          f"NDCG:\t{rank_eval.ndcg_at_k():.6f}\n"
          f"Precision@K:\t{rank_eval.precision_at_k():.6f}\n"
          f"Recall@K:\t{rank_eval.recall_at_k():.6f}\n"
          f"RMSE:\t{rating_eval.rmse():.6f}\n"
          f"MAE:\t{rating_eval.mae():.6f}\n"
          f"Explained variance:\t{rating_eval.exp_var():.6f}\n"
          f"R squared:\t{rating_eval.rsquared():.6f}")

    总结

    本篇文章以 als_movielens.ipynb 为例,详细介绍了如何使用 PySpark 实现基于 ALS 算法的电影推荐系统,并对模型性能进行了评估。 ALS 算法原理简单,易于实现,并且可以通过调节参数来控制模型的复杂度,适用于各种规模的数据集。

  • 快速上手推荐系统:微软 Recommenders 示例精解

    引言

    想要快速体验不同推荐算法的魅力,并构建自己的推荐系统原型?微软 Recommenders 工具的 00_quick_start 目录提供了一系列开箱即用的 Jupyter Notebook 示例,涵盖了从数据准备、模型构建到模型评估的完整流程。

    示例概览

    00_quick_start 目录下的示例 Notebook 涵盖了多种经典和先进的推荐算法,并使用了不同的数据集和运行环境,具体如下表所示:

    示例数据集运行环境描述
    alsMovieLensPySpark使用交替最小二乘法 (ALS) 预测电影评分,在 PySpark 环境中运行。
    dknMINDPython CPU, GPU使用深度知识感知网络 (DKN) 进行新闻推荐,利用知识图谱信息,在 Python+GPU (TensorFlow) 环境中运行。
    fastaiMovieLensPython CPU, GPU使用 FastAI 推荐系统预测电影评分,在 Python+GPU (PyTorch) 环境中运行。

    注意: 表格中只列举了部分示例,完整列表请参考 README.md

    示例详解

    下面以 sar_movielens.ipynb 为例,介绍如何使用 Recommenders 快速构建一个简单的推荐系统。

    1. 数据准备

    该示例使用了 MovieLens 数据集,其中包含用户对电影的评分信息。首先,需要使用 recommenders.datasets.movielens 模块加载数据集。

    from recommenders.datasets.movielens import load_pandas_dataframe
    
    # 加载 MovieLens 100k 数据集
    df = load_pandas_dataframe(size='100k')

    2. 模型构建

    该示例使用了简单的推荐算法 (SAR),该算法基于用户历史行为计算物品之间的相似度,并根据相似度进行推荐。

    from recommenders.models.sar import SAR
    
    # 创建 SAR 模型
    model = SAR(
        col_user="userID",
        col_item="itemID",
        col_rating="rating",
        similarity_type="cosine",
        time_decay_coefficient=1.0,
        time_unit="week",
    )
    
    # 训练模型
    model.fit(df)

    3. 模型评估

    模型训练完成后,可以使用 recommenders.evaluation.python_evaluation 模块中的评估指标对模型进行评估。

    from recommenders.evaluation.python_evaluation import map_at_k, ndcg_at_k
    
    # 生成推荐结果
    top_k = 10
    user_ids = df["userID"].unique()
    recommendations = model.recommend_k_items(df, user_ids, top_k=top_k)
    
    # 计算评估指标
    map_value = map_at_k(df, recommendations, col_user="userID", col_item="itemID", col_rating="rating", k=top_k)
    ndcg_value = ndcg_at_k(df, recommendations, col_user="userID", col_item="itemID", col_rating="rating", k=top_k)
    
    print(f"MAP@{top_k}: {map_value:.4f}")
    print(f"NDCG@{top_k}: {ndcg_value:.4f}")

    总结

    微软 Recommenders 提供的快速入门示例可以帮助您快速了解不同推荐算法的原理和使用方法,并构建自己的推荐系统原型。