@@ -253,23 +253,6 @@ struct EvalRank : public MetricNoCache, public EvalRankConfig {
253
253
virtual double EvalGroup (PredIndPairContainer *recptr) const = 0;
254
254
};
255
255
256
- /* ! \brief Precision at N, for both classification and rank */
257
- struct EvalPrecision : public EvalRank {
258
- public:
259
- explicit EvalPrecision (const char * name, const char * param) : EvalRank(name, param) {}
260
-
261
- double EvalGroup (PredIndPairContainer *recptr) const override {
262
- PredIndPairContainer &rec (*recptr);
263
- // calculate Precision
264
- std::stable_sort (rec.begin (), rec.end (), common::CmpFirst);
265
- unsigned nhit = 0 ;
266
- for (size_t j = 0 ; j < rec.size () && j < this ->topn ; ++j) {
267
- nhit += (rec[j].second != 0 );
268
- }
269
- return static_cast <double >(nhit) / this ->topn ;
270
- }
271
- };
272
-
273
256
/* ! \brief Cox: Partial likelihood of the Cox proportional hazards model */
274
257
struct EvalCox : public MetricNoCache {
275
258
public:
@@ -321,10 +304,6 @@ XGBOOST_REGISTER_METRIC(AMS, "ams")
321
304
.describe(" AMS metric for higgs." )
322
305
.set_body([](const char * param) { return new EvalAMS (param); });
323
306
324
- XGBOOST_REGISTER_METRIC (Precision, " pre" )
325
- .describe(" precision@k for rank." )
326
- .set_body([](const char * param) { return new EvalPrecision (" pre" , param); });
327
-
328
307
XGBOOST_REGISTER_METRIC (Cox, " cox-nloglik" )
329
308
.describe(" Negative log partial likelihood of Cox proportional hazards model." )
330
309
.set_body([](const char *) { return new EvalCox (); });
@@ -387,6 +366,8 @@ class EvalRankWithCache : public Metric {
387
366
return result;
388
367
}
389
368
369
+ [[nodiscard]] const char * Name () const override { return name_.c_str (); }
370
+
390
371
virtual double Eval (HostDeviceVector<float > const & preds, MetaInfo const & info,
391
372
std::shared_ptr<Cache> p_cache) = 0;
392
373
};
@@ -408,6 +389,51 @@ double Finalize(MetaInfo const& info, double score, double sw) {
408
389
}
409
390
} // namespace
410
391
392
+ class EvalPrecision : public EvalRankWithCache <ltr::MAPCache> {
393
+ public:
394
+ using EvalRankWithCache::EvalRankWithCache;
395
+ double Eval (HostDeviceVector<float > const & predt, MetaInfo const & info,
396
+ std::shared_ptr<ltr::MAPCache> p_cache) final {
397
+ // Fixme: check whether minus is applicable here.
398
+ if (ctx_->IsCUDA ()) {
399
+ auto pre = cuda_impl::PreScore (ctx_, info, predt, minus_, p_cache);
400
+ return Finalize (info, pre.Residue (), pre.Weights ());
401
+ }
402
+
403
+ auto gptr = p_cache->DataGroupPtr (ctx_);
404
+ auto h_label = info.labels .HostView ().Slice (linalg::All (), 0 );
405
+ auto h_predt = linalg::MakeTensorView (ctx_, &predt, predt.Size ());
406
+ auto rank_idx = p_cache->SortedIdx (ctx_, predt.ConstHostSpan ());
407
+
408
+ auto pre = p_cache->Map (ctx_);
409
+ auto topk = p_cache->Param ().TopK ();
410
+
411
+ common::ParallelFor (p_cache->Groups (), ctx_->Threads (), [&](auto g) {
412
+ auto g_label = h_label.Slice (linalg::Range (gptr[g], gptr[g + 1 ]));
413
+ auto g_rank = rank_idx.subspan (gptr[g]);
414
+
415
+ auto n = std::min (static_cast <std::size_t >(param_.TopK ()), g_label.Size ());
416
+ double n_hits{0.0 };
417
+ for (std::size_t i = 0 ; i < n; ++i) {
418
+ n_hits += g_label (g_rank[i]);
419
+ }
420
+ pre[g] = n_hits / topk;
421
+ });
422
+
423
+ auto sw = 0.0 ;
424
+ auto weight = common::MakeOptionalWeights (ctx_, info.weights_ );
425
+ if (!weight.Empty ()) {
426
+ CHECK_EQ (weight.weights .size (), p_cache->Groups ());
427
+ }
428
+ for (std::size_t i = 0 ; i < pre.size (); ++i) {
429
+ pre[i] = pre[i] * weight[i];
430
+ sw += weight[i];
431
+ }
432
+ auto sum = std::accumulate (pre.cbegin (), pre.cend (), 0.0 );
433
+ return Finalize (info, sum, sw);
434
+ }
435
+ };
436
+
411
437
/* *
412
438
* \brief Implement the NDCG score function for learning to rank.
413
439
*
@@ -416,7 +442,6 @@ double Finalize(MetaInfo const& info, double score, double sw) {
416
442
class EvalNDCG : public EvalRankWithCache <ltr::NDCGCache> {
417
443
public:
418
444
using EvalRankWithCache::EvalRankWithCache;
419
- const char * Name () const override { return name_.c_str (); }
420
445
421
446
double Eval (HostDeviceVector<float > const & preds, MetaInfo const & info,
422
447
std::shared_ptr<ltr::NDCGCache> p_cache) override {
@@ -475,7 +500,6 @@ class EvalNDCG : public EvalRankWithCache<ltr::NDCGCache> {
475
500
class EvalMAPScore : public EvalRankWithCache <ltr::MAPCache> {
476
501
public:
477
502
using EvalRankWithCache::EvalRankWithCache;
478
- const char * Name () const override { return name_.c_str (); }
479
503
480
504
double Eval (HostDeviceVector<float > const & predt, MetaInfo const & info,
481
505
std::shared_ptr<ltr::MAPCache> p_cache) override {
@@ -527,6 +551,10 @@ class EvalMAPScore : public EvalRankWithCache<ltr::MAPCache> {
527
551
}
528
552
};
529
553
554
+ XGBOOST_REGISTER_METRIC (Precision, " pre" )
555
+ .describe(" precision@k for rank." )
556
+ .set_body([](const char * param) { return new EvalPrecision (" pre" , param); });
557
+
530
558
XGBOOST_REGISTER_METRIC (EvalMAP, " map" )
531
559
.describe(" map@k for ranking." )
532
560
.set_body([](char const * param) {
0 commit comments