dotnet / dotnet/machinelearning

Trivial estimators should also be ITransformer

Open
#2,354 1 comment 1 reaction 1 assignee Claimed by @artidoro View on GitHub
api-suggestion area-Core enhancement Priority:2
Dominant language
C#
Stars
9.4k
Forks
2k
Avg merge
2d 20h
Merged PRs (30d)
11

Description

We are making constructors of transformers internal as part of issue #1798. This makes the creation of non trainable transformers somewhat clumsy. This problem is already reported in the following issue #2165 by an external user.
Here is an example:

```csharp
IDataView data = ...
var estimator = mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel");
var transformer = estimator.Fit(ANY DATA);
var transformedData = transformer.Transform(data);
```
The problem here is the step where the call to `Fit()` is completely useless and feels silly. However, we need estimators for non trainable transformers to use them in estimator pipelines, and the estimator interface cannot change.

One possible approach that we came up with @glebuk and @TomFinley is to make the 'trivial' estimators (estimators for non trainable transformers) `ITransformers` themselves. This is how the API would look like if we make this change, you can see that it is still possible to make the trivial estimators part of a pipeline:
```csharp
IDataView data = ...
var estimatorTransformer = mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel");
var transformedData = estimatorTransformer.Transform(data);

var pipeline = estimatorTransformer.Append(ml.Regression.Learners.FastTree(options);
var trainedPipeline = pipeline.Fit(data);
var transformedData2 = trainedPipeline.Transform(data);
```

The conversion would be very simple. The estimator will have a field `ITransformer Transformer` which is instantiated in the constructor using the arguments passed to the constructor of the estimator (this is already done in cases where the estimator derive from `TrivialEstimator` which should be the case for non trainable estimators). The methods of the interface `ITransformer` will be implemented by calling the respective methods of `Transformer`. A sample conversion should look like the following:

```csharp
public sealed class KeyToValueMappingEstimator : TrivialEstimator, ITransformer
{
public KeyToValueMappingEstimator(IHostEnvironment env, string columnName)
: base(Contracts.CheckRef(env, nameof(env)).Register(nameof(KeyToValueMappingEstimator)), new KeyToValueMappingTransformer(env, columnName))
{ }

public KeyToValueMappingEstimator(IHostEnvironment env, params (string outputColumnName, string inputColumnName)[] columns)
: base(Contracts.CheckRef(env, nameof(env)).Register(nameof(KeyToValueMappingEstimator)), new KeyToValueMappingTransformer(env, columns))
{ }

public override SchemaShape GetOutputSchema(SchemaShape inputSchema)
{ ... }

public bool IsRowToRowMapper => Transformer.IsRowToRowMapper;
public Schema GetOutputSchema(Schema inputSchema) => Transformer.GetOutputSchema(inputSchema);
public IRowToRowMapper GetRowToRowMapper(Schema inputSchema) => Transformer.GetRowToRowMapper(inputSchema);
public IDataView Transform(IDataView input) => Transformer.Transform(input);
}
}
```

/cc @Ivanidzo4ka

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.