Skip to content

Commit ccf8fdd

Browse files
committed
fcc takes transformer instead of model parameters
1 parent c6b53ba commit ccf8fdd

File tree

3 files changed

+74
-16
lines changed

3 files changed

+74
-16
lines changed

src/Microsoft.ML.Data/Transforms/ExplainabilityCatalog.cs

+30-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using Microsoft.ML.Calibrators;
56
using Microsoft.ML.Data;
67
using Microsoft.ML.Trainers;
78
using Microsoft.ML.Transforms;
@@ -36,6 +37,34 @@ public static FeatureContributionCalculatingEstimator CalculateFeatureContributi
3637
int numberOfPositiveContributions = FeatureContributionDefaults.NumberOfPositiveContributions,
3738
int numberOfNegativeContributions = FeatureContributionDefaults.NumberOfNegativeContributions,
3839
bool normalize = FeatureContributionDefaults.Normalize)
39-
=> new FeatureContributionCalculatingEstimator(CatalogUtils.GetEnvironment(catalog), predictionTransformer, numberOfPositiveContributions, numberOfNegativeContributions, normalize);
40+
=> new FeatureContributionCalculatingEstimator(CatalogUtils.GetEnvironment(catalog), predictionTransformer.Model, numberOfPositiveContributions, numberOfNegativeContributions, predictionTransformer.FeatureColumn, normalize);
41+
42+
/// <summary>
43+
/// Feature Contribution Calculation computes model-specific contribution scores for each feature.
44+
/// Note that this functionality is not supported by all the models. See <see cref="FeatureContributionCalculatingTransformer"/> for a list of the suported models.
45+
/// </summary>
46+
/// <param name="catalog">The model explainability operations catalog.</param>
47+
/// <param name="predictionTransformer">A <see cref="ISingleFeaturePredictionTransformer{TModel}"/> that supports Feature Contribution Calculation,
48+
/// and which will also be used for scoring.</param>
49+
/// <param name="numberOfPositiveContributions">The number of positive contributions to report, sorted from highest magnitude to lowest magnitude.
50+
/// Note that if there are fewer features with positive contributions than <paramref name="numberOfPositiveContributions"/>, the rest will be returned as zeros.</param>
51+
/// <param name="numberOfNegativeContributions">The number of negative contributions to report, sorted from highest magnitude to lowest magnitude.
52+
/// Note that if there are fewer features with negative contributions than <paramref name="numberOfNegativeContributions"/>, the rest will be returned as zeros.</param>
53+
/// <param name="normalize">Whether the feature contributions should be normalized to the [-1, 1] interval.</param>
54+
/// <example>
55+
/// <format type="text/markdown">
56+
/// <![CDATA[
57+
/// [!code-csharp[FCT](~/../docs/samples/docs/samples/Microsoft.ML.Samples/Dynamic/FeatureContributionCalculationTransform.cs)]
58+
/// ]]>
59+
/// </format>
60+
/// </example>
61+
public static FeatureContributionCalculatingEstimator CalculateFeatureContribution<TModelParameters, TCalibrator>(this TransformsCatalog catalog,
62+
ISingleFeaturePredictionTransformer<CalibratedModelParametersBase<TModelParameters, TCalibrator>> predictionTransformer,
63+
int numberOfPositiveContributions = FeatureContributionDefaults.NumberOfPositiveContributions,
64+
int numberOfNegativeContributions = FeatureContributionDefaults.NumberOfNegativeContributions,
65+
bool normalize = FeatureContributionDefaults.Normalize)
66+
where TModelParameters : class, ICalculateFeatureContribution
67+
where TCalibrator : class, ICalibrator
68+
=> new FeatureContributionCalculatingEstimator(CatalogUtils.GetEnvironment(catalog), predictionTransformer.Model.SubModel, numberOfPositiveContributions, numberOfNegativeContributions, predictionTransformer.FeatureColumn, normalize);
4069
}
4170
}

src/Microsoft.ML.Data/Transforms/FeatureContributionCalculationTransformer.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -286,22 +286,24 @@ internal static class Defaults
286286
/// Note that this functionality is not supported by all the models. See <see cref="FeatureContributionCalculatingTransformer"/> for a list of the suported models.
287287
/// </summary>
288288
/// <param name="env">The environment to use.</param>
289-
/// <param name="predictionTransformer">A <see cref="ISingleFeaturePredictionTransformer{TModel}"/> that supports Feature Contribution Calculation,
289+
/// <param name="model">A <see cref="ISingleFeaturePredictionTransformer{TModel}"/> that supports Feature Contribution Calculation,
290290
/// and which will also be used for scoring.</param>
291291
/// <param name="numberOfPositiveContributions">The number of positive contributions to report, sorted from highest magnitude to lowest magnitude.
292292
/// Note that if there are fewer features with positive contributions than <paramref name="numberOfPositiveContributions"/>, the rest will be returned as zeros.</param>
293293
/// <param name="numberOfNegativeContributions">The number of negative contributions to report, sorted from highest magnitude to lowest magnitude.
294294
/// Note that if there are fewer features with negative contributions than <paramref name="numberOfNegativeContributions"/>, the rest will be returned as zeros.</param>
295+
/// <param name="featureColumnName">TODO</param>
295296
/// <param name="normalize">Whether the feature contributions should be normalized to the [-1, 1] interval.</param>
296-
internal FeatureContributionCalculatingEstimator(IHostEnvironment env, ISingleFeaturePredictionTransformer<ICalculateFeatureContribution> predictionTransformer,
297+
internal FeatureContributionCalculatingEstimator(IHostEnvironment env, ICalculateFeatureContribution model,
297298
int numberOfPositiveContributions = Defaults.NumberOfPositiveContributions,
298299
int numberOfNegativeContributions = Defaults.NumberOfNegativeContributions,
300+
string featureColumnName = DefaultColumnNames.Features,
299301
bool normalize = Defaults.Normalize)
300302
: base(Contracts.CheckRef(env, nameof(env)).Register(nameof(FeatureContributionCalculatingTransformer)),
301-
new FeatureContributionCalculatingTransformer(env, predictionTransformer.Model, predictionTransformer.FeatureColumn, numberOfPositiveContributions, numberOfNegativeContributions, normalize))
303+
new FeatureContributionCalculatingTransformer(env, model, featureColumnName, numberOfPositiveContributions, numberOfNegativeContributions, normalize))
302304
{
303-
_featureColumn = predictionTransformer.FeatureColumn;
304-
_predictor = predictionTransformer.Model;
305+
_featureColumn = featureColumnName;
306+
_predictor = model;
305307
}
306308

307309
/// <summary>

test/Microsoft.ML.Tests/FeatureContributionTests.cs

+37-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.IO;
7+
using Microsoft.ML.Calibrators;
78
using Microsoft.ML.Data;
89
using Microsoft.ML.Data.IO;
910
using Microsoft.ML.Internal.Utilities;
@@ -174,36 +175,62 @@ public void TestGAMBinary()
174175
}
175176

176177
private void TestFeatureContribution(
177-
ITrainerEstimator<ISingleFeaturePredictionTransformer<IPredictor>, IPredictor> trainer,
178+
ITrainerEstimator<ISingleFeaturePredictionTransformer<ICalculateFeatureContribution>, ICalculateFeatureContribution> trainer,
178179
IDataView data,
179180
string testFile,
180181
int precision = 6)
181182
{
182183
// Train the model.
183184
var model = trainer.Fit(data);
184185

185-
// Extract the predictor, check that it supports feature contribution.
186-
var fccModel = model as ISingleFeaturePredictionTransformer<ICalculateFeatureContribution>;
187-
Assert.NotNull(fccModel);
186+
// Calculate feature contributions.
187+
var est = ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 3, numberOfNegativeContributions: 0)
188+
.Append(ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 0, numberOfNegativeContributions: 3))
189+
.Append(ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 1, numberOfNegativeContributions: 1))
190+
.Append(ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 1, numberOfNegativeContributions: 1, normalize: false));
191+
192+
TestEstimatorCore(est, data);
193+
194+
// Verify output.
195+
CheckOutput(est, data, testFile, precision);
196+
Done();
197+
}
198+
199+
private void TestFeatureContribution<TModelParameters, TCalibrator>(
200+
ITrainerEstimator<ISingleFeaturePredictionTransformer<CalibratedModelParametersBase<TModelParameters, TCalibrator>>, CalibratedModelParametersBase<TModelParameters, TCalibrator>> trainer,
201+
IDataView data,
202+
string testFile,
203+
int precision = 6)
204+
where TModelParameters : class, ICalculateFeatureContribution
205+
where TCalibrator : class, ICalibrator
206+
{
207+
// Train the model.
208+
var model = trainer.Fit(data);
188209

189210
// Calculate feature contributions.
190-
var est = ML.Transforms.CalculateFeatureContribution(fccModel, numberOfPositiveContributions: 3, numberOfNegativeContributions: 0)
191-
.Append(ML.Transforms.CalculateFeatureContribution(fccModel, numberOfPositiveContributions: 0, numberOfNegativeContributions: 3))
192-
.Append(ML.Transforms.CalculateFeatureContribution(fccModel, numberOfPositiveContributions: 1, numberOfNegativeContributions: 1))
193-
.Append(ML.Transforms.CalculateFeatureContribution(fccModel, numberOfPositiveContributions: 1, numberOfNegativeContributions: 1, normalize: false));
211+
var est = ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 3, numberOfNegativeContributions: 0)
212+
.Append(ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 0, numberOfNegativeContributions: 3))
213+
.Append(ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 1, numberOfNegativeContributions: 1))
214+
.Append(ML.Transforms.CalculateFeatureContribution(model, numberOfPositiveContributions: 1, numberOfNegativeContributions: 1, normalize: false));
194215

195216
TestEstimatorCore(est, data);
217+
196218
// Verify output.
219+
CheckOutput(est, data, testFile, precision);
220+
Done();
221+
}
222+
223+
private void CheckOutput(IEstimator<ITransformer> estimator, IDataView data, string testFile, int precision = 6)
224+
{
197225
var outputPath = GetOutputPath("FeatureContribution", testFile + ".tsv");
198226
using (var ch = Env.Start("save"))
199227
{
200228
var saver = new TextSaver(ML, new TextSaver.Arguments { Silent = true, OutputHeader = false });
201-
var savedData = ML.Data.TakeRows(est.Fit(data).Transform(data), 4);
229+
var savedData = ML.Data.TakeRows(estimator.Fit(data).Transform(data), 4);
202230
using (var fs = File.Create(outputPath))
203231
DataSaverUtils.SaveDataView(ch, saver, savedData, fs, keepHidden: true);
204232
}
205233
CheckEquality("FeatureContribution", testFile + ".tsv", digitsOfPrecision: precision);
206-
Done();
207234
}
208235

209236
/// <summary>

0 commit comments

Comments
 (0)