XGBoost - 学习排名

XGBoost 是各种 LTR 应用的最常见选择,例如推荐系统增强、点击率预测和 SEO。在本章中,我们将介绍各种目标函数,引导您完成准备数据的步骤,并提供如何训练模型的示例。

什么是学习排名?

在开始之前,我们将在这里简单解释一下排名是什么。排名是监督机器学习的一个子集。它不是预测单个数据点的结果,而是在收到一组数据点和一个查询后评估一系列数据点,这使其有别于更常见的分类和回归情况。

通常,搜索引擎使用排名来识别最相关的结果。它还可用于推荐事物、根据以前的购买提供相关建议,或者像我一样,识别最有可能赢得下一场比赛的马匹。

XGBoost 有三个可用于排名的目标函数:逐点、成对和列表。这三个目标函数各有优缺点,它们代表确定项目组排名的不同方法。许多来源对它们进行了详尽的描述,但我们将在这里重点介绍要点。

逐点

此技术独立处理每个查询文档对。您所要做的就是给每个查询-文档对一个分数,并构建一个可以预测相关性分数的模型。

考虑以下情况,我们有一个查询-文档对的数据集,每对的相关性分数在 1 到 5 之间。可以通过训练回归模型来预测每对的相关性分数。

逐点方法是一个很好的开始,因为除了易于使用之外,它还出乎意料地强大且难以克服。此方法可以应用于 XGBoost 中的任何典型回归或分类目标函数。请记住调整数据集标签中的任何不平衡。

成对

成对方法评估文档配对并做出决定以最小化无序对的数量。它被 RankNet 等算法使用。

这种方法会一次处理一个查询和两个文档,并调整预测的相关性分数,以便最相关的文档的分数高于最不相关的文档。

与逐点方法相比,它一次考虑问题以及单个文档。在这里,我们希望精确地模拟文档相对于查询的相对顺序。

XGBoost 为该策略提供了一些目标函数 −

  • rank:pairwise: 这是原始的成对损失函数(也称为 RankNet),它将 LambdaRank 与 MART(多重加性回归树)相结合,也称为 LambdaMART。

  • rank:ndcg: NDCG 代表标准化折扣累积增益。它是业界最流行的排名质量指标之一,因为它同时考虑了给定查询的文档的相对顺序和每个页面的相关性得分。此目标函数使用从 NDCG 指标创建的替代梯度来优化模型。

  • rank:map: MAP 代表平均精度。当相关性得分为二进制(0 或 1)时,使用此较短的排名质量指标。如果 MAP 作为评估指标,则通常需要使用此目标函数。

列表式

即使 XGBoost 不使用列表式技术,仍有必要对其进行讨论以确保完整性。它考虑特定查询的整个文档集,试图一次性优化列表的顺序。

由于它分析了所有文档的相对顺序,因此它比逐点和成对程序有所增强,并可能提供更好的结果。 ListMLE 就是一个列表式损失函数的例子。

在尝试选择最佳目标函数时,交叉验证是一种有用的技术,可以为您的问题确定理想的目标函数。Pointwise 完全无效。

学习使用 XGBoost 进行排名

我们将研究如何准备数据并使用强大的机器学习框架 XGBoost 构建学习排名 (LTR) 模型。我们将使用 Microsoft 的 MSLR-WEB10K 真实世界数据集,该数据集在学习排名社区中很受欢迎。此数据集中查询-文档对的相关性评级显示文档与用户查询的匹配程度。

步骤 1:准备数据

学习排名是搜索引擎用来根据相关性对结果进行排名的策略。此集合中给出的是:此人试图寻找什么?显示了用户的结果。此外,每个文档的相关性分数(四为最高相关性级别)显示了其与查询相比的相关性级别。分数范围是 0 到 4。

在创建模型之前,我们必须导入一些用于数据处理的关键库 −

import pandas as pd
import numpy as np
from sklearn.datasets import load_svmlight_file

这些库使数据处理变得容易。NumPy 用于数值计算,Pandas 用于数据操作。使用 sklearn.datasets 中的 load_svmlight_file 方法以文本格式加载庞大的多特征数据集。

之后,我们将加载我们的训练和验证数据集 −

train = load_svmlight_file(str(data_path / '/Python/vali.txt'), query_id=True)
valid = load_svmlight_file(str(data_path / '/Python/test.txt'), query_id=True)

我们模型的训练和测试数据存储在这里的 train 和 valid 中。每个数据集由三个组件组成:目标向量(相关性分数)、特征矩阵(表示文档质量)和查询 ID(用于将文档分组到同一查询下)。

现在我们将这些解压到变量中以便于使用它们−

X_train, y_train, qid_train = train
X_valid, y_valid, qid_valid = valid

现在,X_train 和 X_valid 是特征矩阵,y_train 和 y_valid 是相关性分数,qid_train 和 qid_valid 用于按查询对文档进行分组。我们可以使用此方法复制排名任务。

步骤 2:训练 XGBRanker

在训练过程中,我们构建一个模型,根据文档与查询的相关性对其进行排名。通过导入 XGBoost 库,我们将首先创建 XGBRanker 类,该类用于涉及学习排名的任务。

import xgboost as xgb
model = xgb.XGBRanker(tree_method="hist", objective="rank:ndcg")

这里,

  • tree_method="hist" 是一种快速生成决策树的方法。

  • objective="rank:ndcg" 设置旨在优化标准化折现累积增益 (NDCG),这是一种常用于排名活动的统计数据。

接下来,我们将模型拟合到训练数据 −

model.fit(X_train, y_train, qid=qid_train)

在本例中,我们传递查询 ID (qid_train)、特征矩阵 (X_train) 和相关性分数 (y_train)。排名过程中的一个重要阶段是使用查询 ID 对属于同一查询的文档进行分组。

步骤 3:预测相关性分数

模型经过训练后,我们可以使用它进行预测。通常,一次预测单个查询的相关性对排名很有帮助。假设我们想要预测验证集中第一个查询的结果 −

X_query = X_valid[qid_valid == qids[0]]

这里,X_query 包含与初始查询相关的所有文档。现在,我们可以通过应用 − 来预测它们的相关性分数

y_pred = model.predict(X_query)

计算出的分数将显示每个文档与其他文档的相关性。通过对这些预测进行排序,可以对文档进行评分;分数越高,相关性越高。

步骤 4:使用 NDCG 评估模型

我们使用一种称为标准化折现累积增益 (NDCG) 的指标来评估我们的排名系统的有效性。此统计数据评估排名准确反映论文实际重要性的程度。以下是 NDCG 计算函数 −

def ndcg(y_score, y_true, k):
   order = np.argsort(y_score)[::-1]
   y_true = np.take(y_true, order[:k])

   gain = 2 ** y_true - 1
   discounts = np.log2(np.arange(len(y_true)) + 2)
   return np.sum(gain / discounts)

通过比较预期分数 (y_score) 和实际相关性分数 (y_true),此函数计算 NDCG。我们遍历验证集中的每个查询并计算 NDCG 分数 −

ndcg_ = list()
qids = np.unique(qid_valid)

for i, qid in enumerate(qids):
   y = y_valid[qid_valid == qid]
    
   if np.sum(y) == 0:
      continue
    
   p = model.predict(X_valid[qid_valid == qid])
   idcg = ndcg(y, y, k=10)
   ndcg_.append(ndcg(p, y, k=10) / idcg)

最后,我们计算每个查询的平均 NDCG 分数 −

np.mean(ndcg_)

所以我们剩下的只是一个代表我们模型整体表现的分数。更高的 NDCG 分数表示更高的排名质量。