Skip to content

Added RankingEvaluatorOptions and removed the truncation limit. #4081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
8749a10
Merge pull request #1 from dotnet/master
harishsk Jun 20, 2019
fe25bf6
Fixed build errors resulting from upgrade to VS2019 compilers
harishsk Jun 21, 2019
cb446be
Added additional message describing the previous fix
harishsk Jun 21, 2019
b5ee220
Merge pull request #2 from dotnet/master
harishsk Jun 21, 2019
b9a7471
Merge pull request #3 from dotnet/master
harishsk Jun 24, 2019
80e238d
Merge pull request #4 from dotnet/master
harishsk Jun 27, 2019
2ef424d
Merge pull request #5 from dotnet/master
harishsk Jul 9, 2019
3958f01
Merge pull request #6 from dotnet/master
harishsk Aug 7, 2019
56d4595
Fixed #3993
harishsk Aug 7, 2019
00bc7ef
Merge pull request #7 from dotnet/master
harishsk Aug 14, 2019
d0462f1
Merge pull request #8 from dotnet/master
harishsk Aug 16, 2019
87cefbc
Merge branch 'master' into bugfix_3993
harishsk Aug 16, 2019
c3a908b
Reverted previous change and added a separate class to control evalua…
harishsk Aug 21, 2019
c0a430a
Merge pull request #9 from dotnet/master
harishsk Aug 21, 2019
0b55903
Syncing upstream fork (#10)
harishsk Aug 30, 2019
56983d5
Syncing upstream fork (#11)
harishsk Aug 30, 2019
3382d1d
Merge pull request #13 from dotnet/master
harishsk Sep 6, 2019
8ca5d01
Merge remote-tracking branch 'upstream/master'
harishsk Sep 10, 2019
4ac459e
Added unit test for ranking evaluation with options
harishsk Sep 11, 2019
8f20ea4
Merge remote-tracking branch 'upstream/master'
harishsk Sep 11, 2019
f9f9e1d
Changed visibility of OutputGroupSummary to internal until we expose …
harishsk Sep 11, 2019
21cb8f3
Added a unit test for maml ranking evaluation
harishsk Sep 12, 2019
138f201
Merge remote-tracking branch 'upstream/master'
harishsk Sep 13, 2019
55e3460
Merge remote-tracking branch 'upstream/master'
harishsk Sep 13, 2019
e43bba3
Merge remote-tracking branch 'upstream/master'
harishsk Sep 16, 2019
421d713
Merge branch 'master' of ssh://github.com/harishsk/machinelearning
harishsk Sep 16, 2019
4f4f81c
Merge remote-tracking branch 'upstream/master'
harishsk Sep 17, 2019
89082a5
Merge branch 'master' into bugfix_3993
harishsk Sep 17, 2019
f167af8
Merge branch 'master' of ssh://github.com/harishsk/machinelearning
harishsk Sep 17, 2019
0d4d34f
getting rid of maxTruncationLevel
Lynx1820 Sep 18, 2019
6cd2f15
removed unnecessary imports
Lynx1820 Sep 18, 2019
1424ab3
removed old comment
Lynx1820 Sep 18, 2019
3ee03ca
removed old comment
Lynx1820 Sep 18, 2019
34b7a91
Merge remote-tracking branch 'upstream/master'
harishsk Sep 19, 2019
5539127
Merge remote-tracking branch 'upstream/master'
harishsk Sep 19, 2019
02053a6
adding a maml baseline test
Lynx1820 Sep 23, 2019
35ad3c0
reformatted maml test and moved to where all the other maml tests are
Lynx1820 Sep 25, 2019
0eb3e2b
Reverted back some spacing. Accidentally reverted some changes in Eva…
Lynx1820 Sep 25, 2019
a3291b1
added more relaxed precision
Lynx1820 Sep 25, 2019
37af437
Merge remote-tracking branch 'upstream/master'
harishsk Sep 26, 2019
68f1f35
baseline precision set 1
Lynx1820 Sep 26, 2019
5b90a34
added more helpful debugging comment
Lynx1820 Sep 26, 2019
0efe238
temp
Lynx1820 Sep 27, 2019
b6584aa
Merge remote-tracking branch 'upstream/master'
harishsk Sep 27, 2019
7d47832
Merge branch 'master' of ssh://github.com/harishsk/machinelearning
harishsk Sep 27, 2019
0e99776
Merge branch 'master' into bugfix_3993
harishsk Sep 27, 2019
20a4490
Revert "temp"
Lynx1820 Sep 30, 2019
0d111f4
Revert "added more relaxed precision"
Lynx1820 Sep 30, 2019
72d1a4d
using fastRankRanking to test RankingEvaluator instead of lightgbm
Lynx1820 Sep 30, 2019
ea9ebed
Merge branch 'bugfix_3993' of git://github.com/harishsk/machinelearni…
Lynx1820 Sep 30, 2019
013be4f
reverted some indenting and LightGBM imports
Lynx1820 Sep 30, 2019
d2ae365
removed the stratification flag to get real numbers
Lynx1820 Oct 7, 2019
a9e6db8
testcase change added
Lynx1820 Oct 7, 2019
5855f99
Added the Bestfriend attribute back
Lynx1820 Oct 7, 2019
724bb12
Changed implementation of discount map computation to minimize mutabl…
harishsk Oct 9, 2019
d009f55
Added doc strings
harishsk Oct 9, 2019
8f7b6cd
Fixed bug in creation of fixed discount map
harishsk Oct 9, 2019
30d56a0
Merge remote-tracking branch 'upstream/master' into bugfix_3993
harishsk Oct 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 80 additions & 56 deletions src/Microsoft.ML.Data/Evaluators/RankingEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
using Microsoft.ML.Internal.Utilities;
using Microsoft.ML.Runtime;

[assembly: LoadableClass(typeof(RankingEvaluator), typeof(RankingEvaluator), typeof(RankingEvaluator.Arguments), typeof(SignatureEvaluator),
[assembly: LoadableClass(typeof(RankingEvaluator), typeof(RankingEvaluator), typeof(RankingEvaluatorOptions), typeof(SignatureEvaluator),
"Ranking Evaluator", RankingEvaluator.LoadName, "Ranking", "rank")]

[assembly: LoadableClass(typeof(RankingMamlEvaluator), typeof(RankingMamlEvaluator), typeof(RankingMamlEvaluator.Arguments), typeof(SignatureMamlEvaluator),
Expand All @@ -26,21 +26,30 @@

namespace Microsoft.ML.Data
{
[BestFriend]
internal sealed class RankingEvaluator : EvaluatorBase<RankingEvaluator.Aggregator>
/// <summary>
/// Options to control the output of the RankingEvaluator
/// </summary>
public sealed class RankingEvaluatorOptions
{
public sealed class Arguments
{
[Argument(ArgumentType.AtMostOnce, HelpText = "Maximum truncation level for computing (N)DCG", ShortName = "t")]
public int DcgTruncationLevel = 3;
/// <value>
/// Maximum truncation level for computing (N)DCG
/// </value>
[Argument(ArgumentType.AtMostOnce, HelpText = "Maximum truncation level for computing (N)DCG", ShortName = "t")]
public int DcgTruncationLevel = 3;

[Argument(ArgumentType.AtMostOnce, HelpText = "Label relevance gains", ShortName = "gains")]
public string LabelGains = "0,3,7,15,31";
/// <value>
/// Label relevance gains
/// </value>
[Argument(ArgumentType.AtMostOnce, HelpText = "Label relevance gains", ShortName = "gains")]
public string LabelGains = "0,3,7,15,31";

[Argument(ArgumentType.AtMostOnce, HelpText = "Generate per-group (N)DCG", ShortName = "ogs")]
public bool OutputGroupSummary;
}
[Argument(ArgumentType.AtMostOnce, HelpText = "Generate per-group (N)DCG", ShortName = "ogs")]
internal bool OutputGroupSummary;
}

[BestFriend]
internal sealed class RankingEvaluator : EvaluatorBase<RankingEvaluator.Aggregator>
{
internal const string LoadName = "RankingEvaluator";

public const string Ndcg = "NDCG";
Expand All @@ -60,24 +69,25 @@ public sealed class Arguments
private readonly bool _groupSummary;
private readonly Double[] _labelGains;

public RankingEvaluator(IHostEnvironment env, Arguments args)
public RankingEvaluator(IHostEnvironment env, RankingEvaluatorOptions options)
: base(env, LoadName)
{
// REVIEW: What kind of checking should be applied to labelGains?
if (args.DcgTruncationLevel <= 0 || args.DcgTruncationLevel > Aggregator.Counters.MaxTruncationLevel)
throw Host.ExceptUserArg(nameof(args.DcgTruncationLevel), "DCG Truncation Level must be between 1 and {0}", Aggregator.Counters.MaxTruncationLevel);
Host.CheckUserArg(args.LabelGains != null, nameof(args.LabelGains), "Label gains cannot be null");
// add the setter to utils here
if (options.DcgTruncationLevel <= 0)
throw Host.ExceptUserArg(nameof(options.DcgTruncationLevel), "DCG Truncation Level must be greater than 0");
Host.CheckUserArg(options.LabelGains != null, nameof(options.LabelGains), "Label gains cannot be null");

_truncationLevel = args.DcgTruncationLevel;
_groupSummary = args.OutputGroupSummary;
_truncationLevel = options.DcgTruncationLevel;
_groupSummary = options.OutputGroupSummary;

var labelGains = new List<Double>();
string[] gains = args.LabelGains.Split(',');
string[] gains = options.LabelGains.Split(',');
for (int i = 0; i < gains.Length; i++)
{
Double gain;
if (!Double.TryParse(gains[i], out gain))
throw Host.ExceptUserArg(nameof(args.LabelGains), "Label Gains must be of floating or integral type", Aggregator.Counters.MaxTruncationLevel);
throw Host.ExceptUserArg(nameof(options.LabelGains), "Label Gains must be of floating or integral type");
labelGains.Add(gain);
}
_labelGains = labelGains.ToArray();
Expand Down Expand Up @@ -271,8 +281,6 @@ public sealed class Aggregator : AggregatorBase
{
public sealed class Counters
{
public const int MaxTruncationLevel = 10;

public readonly int TruncationLevel;
private readonly List<Double[]> _groupNdcg;
private readonly List<Double[]> _groupDcg;
Expand All @@ -287,6 +295,7 @@ public sealed class Counters
private readonly List<short> _queryLabels;
private readonly List<Single> _queryOutputs;
private readonly Double[] _labelGains;
private readonly Double[] _discountMap;

public bool GroupSummary { get { return _groupNdcg != null; } }

Expand Down Expand Up @@ -348,6 +357,8 @@ public Counters(Double[] labelGains, int truncationLevel, bool groupSummary)
Contracts.AssertValue(labelGains);

TruncationLevel = truncationLevel;
_discountMap = RankingUtils.GetDiscountMap(truncationLevel);

_sumDcgAtN = new Double[TruncationLevel];
_sumNdcgAtN = new Double[TruncationLevel];

Expand All @@ -373,15 +384,15 @@ public void Update(short label, Single output)

public void UpdateGroup(Single weight)
{
RankingUtils.QueryMaxDcg(_labelGains, TruncationLevel, _queryLabels, _queryOutputs, _groupMaxDcgCur);
RankingUtils.QueryMaxDcg(_labelGains, TruncationLevel, _discountMap, _queryLabels, _queryOutputs, _groupMaxDcgCur);
if (_groupMaxDcg != null)
{
var maxDcg = new Double[TruncationLevel];
Array.Copy(_groupMaxDcgCur, maxDcg, TruncationLevel);
_groupMaxDcg.Add(maxDcg);
}

RankingUtils.QueryDcg(_labelGains, TruncationLevel, _queryLabels, _queryOutputs, _groupDcgCur);
RankingUtils.QueryDcg(_labelGains, TruncationLevel, _discountMap, _queryLabels, _queryOutputs, _groupDcgCur);
if (_groupDcg != null)
{
var groupDcg = new Double[TruncationLevel];
Expand Down Expand Up @@ -684,17 +695,19 @@ private void SlotNamesGetter(int iinfo, ref VBuffer<ReadOnlyMemory<char>> dst)

private readonly Bindings _bindings;
private readonly int _truncationLevel;
private readonly Double[] _discountMap;
private readonly Double[] _labelGains;

public Transform(IHostEnvironment env, IDataView input, string labelCol, string scoreCol, string groupCol,
int truncationLevel, Double[] labelGains)
: base(env, input, labelCol, scoreCol, groupCol, RegistrationName)
{
Host.CheckParam(0 < truncationLevel && truncationLevel < 100, nameof(truncationLevel),
"Truncation level must be between 1 and 99");
Host.CheckParam(0 < truncationLevel , nameof(truncationLevel),
"Truncation level must be greater than 0");
Host.CheckValue(labelGains, nameof(labelGains));

_truncationLevel = truncationLevel;
_discountMap = RankingUtils.GetDiscountMap(_truncationLevel);
_labelGains = labelGains;
_bindings = new Bindings(Host, Source.Schema, true, LabelCol, ScoreCol, GroupCol, _truncationLevel);
}
Expand All @@ -709,7 +722,7 @@ public Transform(IHostEnvironment env, ModelLoadContext ctx, IDataView input)
// double[]: _labelGains

_truncationLevel = ctx.Reader.ReadInt32();
Host.CheckDecode(0 < _truncationLevel && _truncationLevel < 100);
Host.CheckDecode(0 < _truncationLevel);
_labelGains = ctx.Reader.ReadDoubleArray();
_bindings = new Bindings(Host, input.Schema, false, LabelCol, ScoreCol, GroupCol, _truncationLevel);
}
Expand All @@ -725,7 +738,7 @@ private protected override void SaveModel(ModelSaveContext ctx)
// double[]: _labelGains

base.SaveModel(ctx);
Host.Assert(0 < _truncationLevel && _truncationLevel < 100);
Host.Assert(0 < _truncationLevel);
ctx.Writer.Write(_truncationLevel);
ctx.Writer.WriteDoubleArray(_labelGains);
}
Expand Down Expand Up @@ -800,9 +813,9 @@ protected override void ProcessExample(RowCursorState state, short label, Single
protected override void UpdateState(RowCursorState state)
{
// Calculate the current group DCG, NDCG and MaxDcg.
RankingUtils.QueryMaxDcg(_labelGains, _truncationLevel, state.QueryLabels, state.QueryOutputs,
RankingUtils.QueryMaxDcg(_labelGains, _truncationLevel, _discountMap, state.QueryLabels, state.QueryOutputs,
state.MaxDcgCur);
RankingUtils.QueryDcg(_labelGains, _truncationLevel, state.QueryLabels, state.QueryOutputs, state.DcgCur);
RankingUtils.QueryDcg(_labelGains, _truncationLevel, _discountMap, state.QueryLabels, state.QueryOutputs, state.DcgCur);
for (int t = 0; t < _truncationLevel; t++)
{
Double ndcg = state.MaxDcgCur[t] > 0 ? state.DcgCur[t] / state.MaxDcgCur[t] : 0;
Expand All @@ -823,7 +836,7 @@ public sealed class RowCursorState

public RowCursorState(int truncationLevel)
{
Contracts.Assert(0 < truncationLevel && truncationLevel < 100);
Contracts.Assert(0 < truncationLevel);

QueryLabels = new List<short>();
QueryOutputs = new List<Single>();
Expand Down Expand Up @@ -867,12 +880,12 @@ public RankingMamlEvaluator(IHostEnvironment env, Arguments args)
Host.CheckValue(args, nameof(args));
Utils.CheckOptionalUserDirectory(args.GroupSummaryFilename, nameof(args.GroupSummaryFilename));

var evalArgs = new RankingEvaluator.Arguments();
evalArgs.DcgTruncationLevel = args.DcgTruncationLevel;
evalArgs.LabelGains = args.LabelGains;
evalArgs.OutputGroupSummary = !string.IsNullOrEmpty(args.GroupSummaryFilename);
var evalOpts = new RankingEvaluatorOptions();
evalOpts.DcgTruncationLevel = args.DcgTruncationLevel;
evalOpts.LabelGains = args.LabelGains;
evalOpts.OutputGroupSummary = !string.IsNullOrEmpty(args.GroupSummaryFilename);

_evaluator = new RankingEvaluator(Host, evalArgs);
_evaluator = new RankingEvaluator(Host, evalOpts);
_groupSummaryFilename = args.GroupSummaryFilename;
_groupIdCol = args.GroupIdColumn;
}
Expand Down Expand Up @@ -946,30 +959,41 @@ private protected override IEnumerable<string> GetPerInstanceColumnsToSave(RoleM

internal static class RankingUtils
{
private static volatile Double[] _discountMap;
public static Double[] DiscountMap
// Truncation levels are typically less than 100. So we maintain a fixed discount map of size 100
// If truncation level greater than 100 is required, we build a new one and return that.
private const int FixedDiscountMapSize = 100;
private static Double[] _discountMapFixed;

private static Double[] GetDiscountMapCore(int truncationLevel)
{
get
var discountMap = new Double[truncationLevel];

for (int i = 0; i < discountMap.Length; i++)
discountMap[i] = 1 / Math.Log(2 + i);

return discountMap;
}

public static Double[] GetDiscountMap(int truncationLevel)
{
var discountMap = _discountMapFixed;
if (discountMap == null)
{
double[] result = _discountMap;
if (result == null)
{
var discountMap = new Double[100]; //Hard to believe anyone would set truncation Level higher than 100
for (int i = 0; i < discountMap.Length; i++)
{
discountMap[i] = 1 / Math.Log(2 + i);
}
Interlocked.CompareExchange(ref _discountMap, discountMap, null);
result = _discountMap;
}
return result;
discountMap = GetDiscountMapCore(FixedDiscountMapSize);
Interlocked.CompareExchange(ref _discountMapFixed, discountMap, null);
discountMap = _discountMapFixed;
}

if (truncationLevel <= discountMap.Length)
return discountMap;

return GetDiscountMapCore(truncationLevel);
}

/// <summary>
/// Calculates natural-based max DCG at all truncations from 1 to truncationLevel.
/// </summary>
public static void QueryMaxDcg(Double[] labelGains, int truncationLevel,
public static void QueryMaxDcg(Double[] labelGains, int truncationLevel, Double[] discountMap,
List<short> queryLabels, List<Single> queryOutputs, Double[] groupMaxDcgCur)
{
Contracts.Assert(Utils.Size(groupMaxDcgCur) == truncationLevel);
Expand All @@ -994,21 +1018,21 @@ public static void QueryMaxDcg(Double[] labelGains, int truncationLevel,
while (labelCounts[topLabel] == 0)
topLabel--;

groupMaxDcgCur[0] = labelGains[topLabel] * DiscountMap[0];
groupMaxDcgCur[0] = labelGains[topLabel] * discountMap[0];
labelCounts[topLabel]--;
for (int t = 1; t < maxTrunc; t++)
{
while (labelCounts[topLabel] == 0)
topLabel--;
groupMaxDcgCur[t] = groupMaxDcgCur[t - 1] + labelGains[topLabel] * DiscountMap[t];
groupMaxDcgCur[t] = groupMaxDcgCur[t - 1] + labelGains[topLabel] * discountMap[t];
labelCounts[topLabel]--;
}
for (int t = maxTrunc; t < truncationLevel; t++)
groupMaxDcgCur[t] = groupMaxDcgCur[t - 1];
}
}

public static void QueryDcg(Double[] labelGains, int truncationLevel,
public static void QueryDcg(Double[] labelGains, int truncationLevel, Double[] discountMap,
List<short> queryLabels, List<Single> queryOutputs, Double[] groupDcgCur)
{
// calculate the permutation
Expand All @@ -1021,7 +1045,7 @@ public static void QueryDcg(Double[] labelGains, int truncationLevel,
Double dcg = 0;
for (int t = 0; t < count; ++t)
{
dcg = dcg + labelGains[queryLabels[permutation[t]]] * DiscountMap[t];
dcg = dcg + labelGains[queryLabels[permutation[t]]] * discountMap[t];
groupDcgCur[t] = dcg;
}
for (int t = count; t < truncationLevel; ++t)
Expand Down
17 changes: 16 additions & 1 deletion src/Microsoft.ML.Data/TrainCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,21 @@ internal RankingTrainers(RankingCatalog catalog)
/// <param name="scoreColumnName">The name of the score column in <paramref name="data"/>.</param>
/// <returns>The evaluation results for these calibrated outputs.</returns>
public RankingMetrics Evaluate(IDataView data,
string labelColumnName = DefaultColumnNames.Label,
string rowGroupColumnName = DefaultColumnNames.GroupId,
string scoreColumnName = DefaultColumnNames.Score) => Evaluate(data, null, labelColumnName, rowGroupColumnName, scoreColumnName);

/// <summary>
/// Evaluates scored ranking data.
/// </summary>
/// <param name="data">The scored data.</param>
/// <param name="options">Options to control the evaluation result.</param>
/// <param name="labelColumnName">The name of the label column in <paramref name="data"/>.</param>
/// <param name="rowGroupColumnName">The name of the groupId column in <paramref name="data"/>.</param>
/// <param name="scoreColumnName">The name of the score column in <paramref name="data"/>.</param>
/// <returns>The evaluation results for these calibrated outputs.</returns>
public RankingMetrics Evaluate(IDataView data,
RankingEvaluatorOptions options,
Copy link
Member

@eerhardt eerhardt Aug 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add at least one new test for this new API? #Resolved

Copy link
Contributor

@justinormont justinormont Aug 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And ensure there is an existing unit test covering the existing MAML interface for RankingEvaluator.

It should look about like:
CV tr=LightGBMRanking eval=RankingEvaluator{t=10} k=2 loader=TextLoader{col=Label:R4:0 col=GroupId:TX:1 col=Features:R4:2-138 header=+} data=MSLR-WEB10K_Fold1.TRAIN.SMALL_10k-rows.tsv xf=HashTransform{col=GroupId} xf=NAHandleTransform{col=Features}

Specifically the eval=RankingEvaluator{t=10} part, where the DCG/NDCG threshold is set.

The output should end in a block of DCG/NDCG@N metrics:

OVERALL RESULTS
---------------------------------------
NDCG@1:             51.879160 (3.2943)
NDCG@2:             52.490449 (1.6035)
NDCG@3:             51.704020 (1.7012)
NDCG@4:             51.495099 (0.8726)
NDCG@5:             51.859874 (0.2759)
NDCG@6:             52.278430 (0.2561)
NDCG@7:             52.641604 (0.4342)
NDCG@8:             52.856661 (0.5255)
NDCG@9:             54.075498 (0.5233)
NDCG@10:            54.692374 (0.6690)
DCG@1:              10.778756 (0.1824)
DCG@2:              15.649059 (0.6480)
DCG@3:              18.580052 (0.5112)
DCG@4:              20.808287 (0.9611)
DCG@5:              22.819410 (1.1504)
DCG@6:              24.494010 (1.2360)
DCG@7:              26.108059 (1.6727)
DCG@8:              27.384487 (1.7825)
DCG@9:              29.079234 (1.8749)
DCG@10:             30.308760 (1.9971)

---------------------------------------
Physical memory usage(MB): 123
Virtual memory usage(MB): 5114
8/22/2019 4:56:55 PM	 Time elapsed(s): 5.534

And it should match the @N set in the RankingEvaluator's t=N. #Resolved

string labelColumnName = DefaultColumnNames.Label,
string rowGroupColumnName = DefaultColumnNames.GroupId,
string scoreColumnName = DefaultColumnNames.Score)
Expand All @@ -647,7 +662,7 @@ public RankingMetrics Evaluate(IDataView data,
Environment.CheckNonEmpty(scoreColumnName, nameof(scoreColumnName));
Environment.CheckNonEmpty(rowGroupColumnName, nameof(rowGroupColumnName));

var eval = new RankingEvaluator(Environment, new RankingEvaluator.Arguments() { });
var eval = new RankingEvaluator(Environment, options ?? new RankingEvaluatorOptions() { });
return eval.Evaluate(data, labelColumnName, rowGroupColumnName, scoreColumnName);
}
}
Expand Down
Loading