Skip to content

Commit d9270c9

Browse files
authored
Improve documentation for Feature Contribution Calculation (#2007)
1 parent bb46fdf commit d9270c9

File tree

7 files changed

+84
-39
lines changed

7 files changed

+84
-39
lines changed

docs/samples/Microsoft.ML.Samples/Dynamic/FeatureContributionCalculationTransform.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ public static void FeatureContributionCalculationTransform_Regression()
5959
// Create a Feature Contribution Calculator
6060
// Calculate the feature contributions for all features given trained model parameters
6161
// And don't normalize the contribution scores
62-
var featureContributionCalculator = mlContext.Model.Explainability.FeatureContributionCalculation(model.Model, model.FeatureColumn, top: 11, normalize: false);
62+
var featureContributionCalculator = mlContext.Model.Explainability.FeatureContributionCalculation(model.Model, model.FeatureColumn, numPositiveContributions: 11, normalize: false);
6363
var outputData = featureContributionCalculator.Fit(scoredData).Transform(scoredData);
6464

6565
// FeatureContributionCalculatingEstimator can be use as an intermediary step in a pipeline.
6666
// The features retained by FeatureContributionCalculatingEstimator will be in the FeatureContribution column.
67-
var pipeline = mlContext.Model.Explainability.FeatureContributionCalculation(model.Model, model.FeatureColumn, top: 11)
67+
var pipeline = mlContext.Model.Explainability.FeatureContributionCalculation(model.Model, model.FeatureColumn, numPositiveContributions: 11)
6868
.Append(mlContext.Regression.Trainers.OrdinaryLeastSquares(featureColumn: "FeatureContributions"));
6969
var outData = featureContributionCalculator.Fit(scoredData).Transform(scoredData);
7070

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ public static class ExplainabilityCatalog
1818
/// <param name="catalog">The model explainability operations catalog.</param>
1919
/// <param name="modelParameters">Trained model parameters that support Feature Contribution Calculation and which will be used for scoring.</param>
2020
/// <param name="featureColumn">The name of the feature column that will be used as input.</param>
21-
/// <param name="top">The number of features with highest positive contributions for each data sample that will be retained in the FeatureContribution column.
22-
/// Note that if there are fewer features with positive contributions than <paramref name="top"/>, the rest will be returned as zeros.</param>
23-
/// <param name="bottom">The number of features with least negative contributions for each data sample that will be retained in the FeatureContribution column.
24-
/// Note that if there are fewer features with negative contributions than <paramref name="bottom"/>, the rest will be returned as zeros.</param>
21+
/// <param name="numPositiveContributions">The number of positive contributions to report, sorted from highest magnitude to lowest magnitude.
22+
/// Note that if there are fewer features with positive contributions than <paramref name="numPositiveContributions"/>, the rest will be returned as zeros.</param>
23+
/// <param name="numNegativeContributions">The number of negative contributions to report, sorted from highest magnitude to lowest magnitude.
24+
/// Note that if there are fewer features with negative contributions than <paramref name="numNegativeContributions"/>, the rest will be returned as zeros.</param>
2525
/// <param name="normalize">Whether the feature contributions should be normalized to the [-1, 1] interval.</param>
2626
public static FeatureContributionCalculatingEstimator FeatureContributionCalculation(this ModelOperationsCatalog.ExplainabilityTransforms catalog,
2727
ICalculateFeatureContribution modelParameters,
2828
string featureColumn = DefaultColumnNames.Features,
29-
int top = FeatureContributionDefaults.Top,
30-
int bottom = FeatureContributionDefaults.Bottom,
29+
int numPositiveContributions = FeatureContributionDefaults.NumPositiveContributions,
30+
int numNegativeContributions = FeatureContributionDefaults.NumNegativeContributions,
3131
bool normalize = FeatureContributionDefaults.Normalize)
32-
=> new FeatureContributionCalculatingEstimator(CatalogUtils.GetEnvironment(catalog), modelParameters, featureColumn, top, bottom, normalize);
32+
=> new FeatureContributionCalculatingEstimator(CatalogUtils.GetEnvironment(catalog), modelParameters, featureColumn, numPositiveContributions, numNegativeContributions, normalize);
3333
}
3434
}

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

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,17 @@
2525
namespace Microsoft.ML.Data
2626
{
2727
/// <summary>
28-
/// The FeatureContributionCalculationTransformer computes model-specific contribution scores for each feature.
28+
/// The FeatureContributionCalculationTransformer computes model-specific per-feature contributions to the score of each example.
2929
/// See the list of currently supported models below.
3030
/// </summary>
3131
/// <remarks>
32+
/// <para>
33+
/// Scoring a dataset with a trained model produces a score, or prediction, for each example. To understand and explain these predictions
34+
/// it can be useful to inspect which features influenced them most significantly. FeatureContributionCalculationTransformer computes a model-specific
35+
/// list of per-feature contributions to the score for each example. These contributions can be positive (they make the score higher) or negative
36+
/// (they make the score lower).
37+
/// </para>
38+
/// <para>
3239
/// Feature Contribution Calculation is currently supported for the following models:
3340
/// Regression:
3441
/// OrdinaryLeastSquares, StochasticDualCoordinateAscent (SDCA), OnlineGradientDescent, PoissonRegression,
@@ -39,8 +46,25 @@ namespace Microsoft.ML.Data
3946
/// FastForest, FastTree, LightGbm
4047
/// Ranking:
4148
/// FastTree, LightGbm
42-
///
49+
/// </para>
50+
/// <para>
51+
/// For linear models, the contribution of a given feature is equal to the product of feature value times the corresponding weight. Similarly,
52+
/// for Generalized Additive Models (GAM), the contribution of a feature is equal to the shape function for the given feature evaluated at
53+
/// the feature value.
54+
/// </para>
55+
/// <para>
56+
/// For tree-based models, the calculation of feature contribution essentially consists in determining which splits in the tree have the most impact
57+
/// on the final score and assigning the value of the impact to the features determining the split. More precisely, the contribution of a feature
58+
/// is equal to the change in score produced by exploring the opposite sub-tree every time a decision node for the given feature is encountered.
59+
/// Consider a simple case with a single decision tree that has a decision node for the binary feature F1. Given an example that has feature F1
60+
/// equal to true, we can calculate the score it would have obtained if we chose the subtree corresponding to the feature F1 being equal to false
61+
/// while keeping the other features constant. The contribution of feature F1 for the given example is the difference between the original score
62+
/// and the score obtained by taking the opposite decision at the node corresponding to feature F1. This algorithm extends naturally to models with
63+
/// many decision trees.
64+
/// </para>
65+
/// <para>
4366
/// See the sample below for an example of how to compute feature importance using the FeatureContributionCalculatingTransformer.
67+
/// </para>
4468
/// </remarks>
4569
/// <example>
4670
/// <format type="text/markdown">
@@ -60,10 +84,10 @@ public sealed class Arguments : TransformInputBase
6084
public string FeatureColumn = DefaultColumnNames.Features;
6185

6286
[Argument(ArgumentType.AtMostOnce, HelpText = "Number of top contributions", SortOrder = 3)]
63-
public int Top = FeatureContributionCalculatingEstimator.Defaults.Top;
87+
public int Top = FeatureContributionCalculatingEstimator.Defaults.NumPositiveContributions;
6488

6589
[Argument(ArgumentType.AtMostOnce, HelpText = "Number of bottom contributions", SortOrder = 4)]
66-
public int Bottom = FeatureContributionCalculatingEstimator.Defaults.Bottom;
90+
public int Bottom = FeatureContributionCalculatingEstimator.Defaults.NumNegativeContributions;
6791

6892
[Argument(ArgumentType.AtMostOnce, HelpText = "Whether or not output of Features contribution should be normalized", ShortName = "norm", SortOrder = 5)]
6993
public bool Normalize = FeatureContributionCalculatingEstimator.Defaults.Normalize;
@@ -98,32 +122,32 @@ private static VersionInfo GetVersionInfo()
98122
/// <param name="env">The environment to use.</param>
99123
/// <param name="modelParameters">Trained model parameters that support Feature Contribution Calculation and which will be used for scoring.</param>
100124
/// <param name="featureColumn">The name of the feature column that will be used as input.</param>
101-
/// <param name="top">The number of features with highest positive contributions for each data sample that will be retained in the FeatureContribution column.
102-
/// Note that if there are fewer features with positive contributions than <paramref name="top"/>, the rest will be returned as zeros.</param>
103-
/// <param name="bottom">The number of features with least negative contributions for each data sample that will be retained in the FeatureContribution column.
104-
/// Note that if there are fewer features with negative contributions than <paramref name="bottom"/>, the rest will be returned as zeros.</param>
125+
/// <param name="numPositiveContributions">The number of positive contributions to report, sorted from highest magnitude to lowest magnitude.
126+
/// Note that if there are fewer features with positive contributions than <paramref name="numPositiveContributions"/>, the rest will be returned as zeros.</param>
127+
/// <param name="numNegativeContributions">The number of negative contributions to report, sorted from highest magnitude to lowest magnitude.
128+
/// Note that if there are fewer features with negative contributions than <paramref name="numNegativeContributions"/>, the rest will be returned as zeros.</param>
105129
/// <param name="normalize">Whether the feature contributions should be normalized to the [-1, 1] interval.</param>
106130
public FeatureContributionCalculatingTransformer(IHostEnvironment env, ICalculateFeatureContribution modelParameters,
107131
string featureColumn = DefaultColumnNames.Features,
108-
int top = FeatureContributionCalculatingEstimator.Defaults.Top,
109-
int bottom = FeatureContributionCalculatingEstimator.Defaults.Bottom,
132+
int numPositiveContributions = FeatureContributionCalculatingEstimator.Defaults.NumPositiveContributions,
133+
int numNegativeContributions = FeatureContributionCalculatingEstimator.Defaults.NumNegativeContributions,
110134
bool normalize = FeatureContributionCalculatingEstimator.Defaults.Normalize)
111135
: base(Contracts.CheckRef(env, nameof(env)).Register(nameof(FeatureContributionCalculatingTransformer)), new[] { (input: featureColumn, output: DefaultColumnNames.FeatureContributions) })
112136
{
113137
Host.CheckValue(modelParameters, nameof(modelParameters));
114138
Host.CheckNonEmpty(featureColumn, nameof(featureColumn));
115-
if (top < 0)
139+
if (numPositiveContributions < 0)
116140
throw Host.Except($"Number of top contribution must be non negative");
117-
if (bottom < 0)
141+
if (numNegativeContributions < 0)
118142
throw Host.Except($"Number of bottom contribution must be non negative");
119143

120144
// If a predictor implements ICalculateFeatureContribution, it also implements the internal interface IFeatureContributionMapper.
121145
// This is how we keep the implementation of feature contribution calculation internal.
122146
_predictor = modelParameters as IFeatureContributionMapper;
123147
Host.AssertValue(_predictor);
124148

125-
Top = top;
126-
Bottom = bottom;
149+
Top = numPositiveContributions;
150+
Bottom = numNegativeContributions;
127151
Normalize = normalize;
128152
}
129153

@@ -258,8 +282,8 @@ public sealed class FeatureContributionCalculatingEstimator : TrivialEstimator<F
258282

259283
public static class Defaults
260284
{
261-
public const int Top = 10;
262-
public const int Bottom = 10;
285+
public const int NumPositiveContributions = 10;
286+
public const int NumNegativeContributions = 10;
263287
public const bool Normalize = true;
264288
}
265289

@@ -270,18 +294,18 @@ public static class Defaults
270294
/// <param name="env">The environment to use.</param>
271295
/// <param name="modelParameters">Trained model parameters that support Feature Contribution Calculation and which will be used for scoring.</param>
272296
/// <param name="featureColumn">The name of the feature column that will be used as input.</param>
273-
/// <param name="top">The number of features with highest positive contributions for each data sample that will be retained in the FeatureContribution column.
274-
/// Note that if there are fewer features with positive contributions than <paramref name="top"/>, the rest will be returned as zeros.</param>
275-
/// <param name="bottom">The number of features with least negative contributions for each data sample that will be retained in the FeatureContribution column.
276-
/// Note that if there are fewer features with negative contributions than <paramref name="bottom"/>, the rest will be returned as zeros.</param>
297+
/// <param name="numPositiveContributions">The number of positive contributions to report, sorted from highest magnitude to lowest magnitude.
298+
/// Note that if there are fewer features with positive contributions than <paramref name="numPositiveContributions"/>, the rest will be returned as zeros.</param>
299+
/// <param name="numNegativeContributions">The number of negative contributions to report, sorted from highest magnitude to lowest magnitude.
300+
/// Note that if there are fewer features with negative contributions than <paramref name="numNegativeContributions"/>, the rest will be returned as zeros.</param>
277301
/// <param name="normalize">Whether the feature contributions should be normalized to the [-1, 1] interval.</param>
278302
public FeatureContributionCalculatingEstimator(IHostEnvironment env, ICalculateFeatureContribution modelParameters,
279303
string featureColumn = DefaultColumnNames.Features,
280-
int top = Defaults.Top,
281-
int bottom = Defaults.Bottom,
304+
int numPositiveContributions = Defaults.NumPositiveContributions,
305+
int numNegativeContributions = Defaults.NumNegativeContributions,
282306
bool normalize = Defaults.Normalize)
283307
: base(Contracts.CheckRef(env, nameof(env)).Register(nameof(FeatureContributionCalculatingTransformer)),
284-
new FeatureContributionCalculatingTransformer(env, modelParameters, featureColumn, top, bottom, normalize))
308+
new FeatureContributionCalculatingTransformer(env, modelParameters, featureColumn, numPositiveContributions, numNegativeContributions, normalize))
285309
{
286310
_featureColumn = featureColumn;
287311
_predictor = modelParameters;

src/Microsoft.ML.FastTree/FastTree.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,6 +2837,18 @@ public abstract class TreeEnsembleModelParameters :
28372837
bool ICanSavePfa.CanSavePfa => true;
28382838

28392839
bool ICanSaveOnnx.CanSaveOnnx(OnnxContext ctx) => true;
2840+
2841+
/// <summary>
2842+
/// Used to determine the contribution of each feature to the score of an example by <see cref="FeatureContributionCalculatingTransformer"/>.
2843+
/// The calculation of feature contribution essentially consists in determining which splits in the tree have the most impact
2844+
/// on the final score and assigning the value of the impact to the features determining the split. More precisely, the contribution of a feature
2845+
/// is equal to the change in score produced by exploring the opposite sub-tree every time a decision node for the given feature is encountered.
2846+
/// Consider a simple case with a single decision tree that has a decision node for the binary feature F1. Given an example that has feature F1
2847+
/// equal to true, we can calculate the score it would have obtained if we chose the subtree corresponding to the feature F1 being equal to false
2848+
/// while keeping the other features constant. The contribution of feature F1 for the given example is the difference between the original score
2849+
/// and the score obtained by taking the opposite decision at the node corresponding to feature F1. This algorithm extends naturally to models with
2850+
/// many decision trees.
2851+
/// </summary>
28402852
public FeatureContributionCalculator FeatureContributionClaculator => new FeatureContributionCalculator(this);
28412853

28422854
public TreeEnsembleModelParameters(IHostEnvironment env, string name, TreeEnsemble trainedEnsemble, int numFeatures, string innerArgs)

src/Microsoft.ML.FastTree/GamTrainer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,11 @@ public abstract class GamModelParametersBase : ModelParametersBase<float>, IValu
668668
ColumnType IValueMapper.InputType => _inputType;
669669
ColumnType IValueMapper.OutputType => _outputType;
670670

671+
/// <summary>
672+
/// Used to determine the contribution of each feature to the score of an example by <see cref="FeatureContributionCalculatingTransformer"/>.
673+
/// For Generalized Additive Models (GAM), the contribution of a feature is equal to the shape function for the given feature evaluated at
674+
/// the feature value.
675+
/// </summary>
671676
public FeatureContributionCalculator FeatureContributionClaculator => new FeatureContributionCalculator(this);
672677

673678
private protected GamModelParametersBase(IHostEnvironment env, string name,

src/Microsoft.ML.StandardLearners/Standard/LinearModelParameters.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ public IEnumerator<float> GetEnumerator()
9999

100100
bool ICanSaveOnnx.CanSaveOnnx(OnnxContext ctx) => true;
101101

102+
/// <summary>
103+
/// Used to determine the contribution of each feature to the score of an example by <see cref="FeatureContributionCalculatingTransformer"/>.
104+
/// For linear models, the contribution of a given feature is equal to the product of feature value times the corresponding weight.
105+
/// </summary>
102106
public FeatureContributionCalculator FeatureContributionClaculator => new FeatureContributionCalculator(this);
103107

104108
/// <summary>

0 commit comments

Comments
 (0)