Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Multicolumn mapping for some estimators - #3066

Merged
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn
Mar 25, 2019
Merged

Multicolumn mapping for some estimators#3066
artidoro merged 4 commits into
dotnet:masterfrom
artidoro:multicolumn

Conversation

@artidoro

@artidoroartidoro commented Mar 22, 2019

Copy link
Copy Markdown
Contributor

Adding multicolumn mapping for some estimators (as per list by @TomFinley and @glebuk):

  • OneHotEncodingEstimator
  • TypeConvertingEstimator
  • KeyToVectorMappingEstimator
  • ValueToKeyMappingEstimator
  • OneHotHashEncodingEstimator
  • MissingValueEstimator
  • FeatureSelectionCatalog.*
  • KeyToValueMappingEstiamtor

Leaving out:

  • TextFeaturizingEstimator (probably requires column specific settings most of the time)
  • NoramlizingEstiamtor (in experimental nuget)

Let me know if I should add more estimators.

Fixes#3068
Related to #2884

@artidoro
artidoroforce-pushed the multicolumn branch 3 times, most recently from d08a2f9 to 0896590CompareMarch 22, 2019 20:39
@artidoroartidoro changed the title WIP: Multicolumn mapping for some estimatorsMulticolumn mapping for some estimatorsMar 22, 2019
@artidoroartidoro self-assigned this Mar 22, 2019
@artidoroartidoro added this to the 0319 milestone Mar 22, 2019
Comment threadsrc/Microsoft.ML.Data/Transforms/ExtensionsCatalog.cs Outdated
/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public readonly string InputColumnName [](start = 7, length = 39)

I'm slightly confuse.
We get rid of ColumnOptions because they were immutable, and now we add another immutable class... #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Will invite you to check with Tom about this, I am just executing what he asked


In reply to: 268333577 [](ancestors = 268333577)

/// <summary>
/// Specifies input and output column names for a transformation.
/// </summary>
public sealed class InputOutputColumnPair

@Ivanidzo4kaIvanidzo4kaMar 22, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 24, length = 21)

what is difference between this one and ColumnOptions? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Not much, I would have used the bellow if it were me, but Tom asked it to be different, for some reason!


In reply to: 268334077 [](ancestors = 268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, a very good reason. ColumnOptions is a struct meant to serve a specific transformer base, and that is involved in the type heirarchy, and in particular something that captured all of the individual settings and state for each mapping. Our goals here were comparatively more modest: we just needed to . Well designed code does what it is designed to do, and in the simplest possible way. There is no need for this to be part of an elaborate type hierarchy -- this was in fact the mistake that led to the issue #2884 being filed, that we'd conflated two distinct techniques for the extremely bad reasoning that they both had to do with "column." (And, of course, if something deals with the same sort of object, obviously they belong in the same type heirarchy, right?)


In reply to: 268334389 [](ancestors = 268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just in case, I'm not talking about ColumnOptions inside Estimator, (for example HashingEstimator.ColumnOptions.
I'm talking about ColumnOptions in this exact file few lines below (line 41)
Only difference I see is Input/output column names is public in this one instead of private in other, and name of class.
Ok, two difference, one below has implicit converter from tuple.

Can we delete ColumnOptions in this file?


In reply to: 268337035 [](ancestors = 268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine. What Artidoro and I had discussed was actually somewhat different. (Or we were talking about two separate things without realizing it.)


In reply to: 268339442 [](ancestors = 268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I guess we were talking about something different, glad we are on the same page.


In reply to: 268760195 [](ancestors = 268760195,268339442,268337035,268334389,268334077)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems good to me. The ColumnOptions I had been talking about (which is to say, the vast majority of things with that name) are as I said meant to serve a different purpose.

We should probably rename them back to ColumnInfo at some point but this can be delayed as they are internal... ummm except one. Whoops. Opened #3078. :) Aside from that, yeah.


In reply to: 268771510 [](ancestors = 268771510,268760195,268339442,268337035,268334389,268334077)

@artidoro

artidoro commented Mar 22, 2019

Copy link
Copy Markdown
ContributorAuthor

Since @ivanbasov asked for it the third commit shows the how this would look like if we removed the ColumnOptions class, and used InputOutputColumnPair.

Let me know what looks better! I will either eliminate this commit or keep it.

Notice that even in commit 3 InputOutputColumnPair is never used inside any transform. #Resolved

@codecov

codecovBot commented Mar 22, 2019

Copy link
Copy Markdown

Codecov Report

Merging #3066 into master will decrease coverage by 0.02%.
The diff coverage is 60.11%.

@@ Coverage Diff @@## master #3066 +/- ##
==========================================
- Coverage 72.53% 72.51% -0.03% 
==========================================
Files 806 806 Lines 144282 144642 +360 Branches 16183 16197 +14 ==========================================
+ Hits 104661 104889 +228 - Misses 35217 35342 +125 - Partials 4404 4411 +7
FlagCoverage Δ
#Debug72.51% <60.11%> (-0.03%)⬇️
#production68.11% <41.59%> (-0.05%)⬇️
#test88.8% <98.18%> (+0.04%)⬆️
Impacted FilesCoverage Δ
src/Microsoft.ML.Transforms/Text/TextCatalog.cs41.66% <0%> (-3.79%)⬇️
src/Microsoft.ML.Transforms/NormalizerCatalog.cs36.36% <0%> (-35.07%)⬇️
...c/Microsoft.ML.ImageAnalytics/ExtensionsCatalog.cs11.11% <0%> (-18.89%)⬇️
...icrosoft.ML.Tests/Transformers/CategoricalTests.cs100% <100%> (ø)⬆️
...sts/Transformers/KeyToBinaryVectorEstimatorTest.cs100% <100%> (ø)⬆️
...Microsoft.ML.Tests/Transformers/NormalizerTests.cs100% <100%> (ø)⬆️
...oft.ML.Tests/Transformers/FeatureSelectionTests.cs100% <100%> (ø)⬆️
...ios/IrisPlantClassificationWithStringLabelTests.cs98.63% <100%> (ø)⬆️
...icrosoft.ML.Tests/Transformers/NAIndicatorTests.cs100% <100%> (ø)⬆️
...crosoft.ML.Tests/Transformers/ValueMappingTests.cs100% <100%> (ø)⬆️
... and 30 more

/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
/// <param name="outputKind">The expected kind of the output column.</param>
public static TypeConvertingEstimator ConvertType(this TransformsCatalog.ConversionTransforms catalog,
InputOutputColumnPair[] columns,

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 36, length = 7)

Don't you need to check for null for the columns arg to avoid null reference exception? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I added the checks thanks for pointing out. I only fixed the extensions that are public. Not those that are internal.


In reply to: 268724517 [](ancestors = 268724517)

=> new KeyToValueMappingEstimator(CatalogUtils.GetEnvironment(catalog), ColumnOptions.ConvertToValueTuples(columns));
/// <param name="catalog">The conversion transform's catalog.</param>
/// <param name="columns">Specifies the names of the columns on which to apply the transformation.</param>
public static KeyToValueMappingEstimator MapKeyToValue(this TransformsCatalog.ConversionTransforms catalog, InputOutputColumnPair[] columns)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 140, length = 7)

also check for null #Resolved

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

public InputOutputColumnPair(string outputColumnName, string inputColumnName = null) [](start = 8, length = 84)

Add another overload for the case when input name = output name. That would make it a lot clearer vs setting one to null. #ByDesign

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Unfortunately I believe that everywhere in the codebase we have the same pattern string outputColumnName, string inputColumnName = null. This is found in all the mlContext extensions for transforms. I can add it here, but I think it would make more sense to stick to the general pattern.


In reply to: 268726871 [](ancestors = 268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We must be consistent. Sorry @glebuk!


In reply to: 268779384 [](ancestors = 268779384,268726871)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok then.


In reply to: 268819893 [](ancestors = 268819893,268779384,268726871)

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Shouldn't it be in reverse - the input be set, but output be optional and equal to input if out is null?? #Closed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

As per #2064 we use the outputColumnName as inputColumnName when inputColumnName is null. We are doing this across the code base.


In reply to: 268727730 [](ancestors = 268727730)

ValueToKeyMappingEstimator.KeyOrdinality keyOrdinality = ValueToKeyMappingEstimator.Defaults.Ordinality,
IDataView keyData = null)
{
var columnOptions = columns.Select(x => new OneHotEncodingEstimator.ColumnOptions(x.OutputColumnName, x.InputColumnName, outputKind, maximumNumberOfKeys, keyOrdinality)).ToArray();

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

columns [](start = 32, length = 7)

check for null here and elsewhere #Resolved

("out1", "VectorFloat"),
("out2", "VectorDouble")
columns: new[] {
new InputOutputColumnPair("out1", "VectorFloat"),

@glebukglebukMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputOutputColumnPair [](start = 28, length = 21)

why do we have to use the more verbose initializer here? Ideally we should use the old syntax is possible as it is a lot more compact. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Because the other one uses tuples. We have decided not to have tuples in the public surface any longer.


In reply to: 268729946 [](ancestors = 268729946)

@glebuk

Copy link
Copy Markdown
Contributor
 public void ValueMappingValueTypeIsVectorWorkout()

Add a test for when InputOutputColumnPair is null.


Refers to: test/Microsoft.ML.Tests/Transformers/ValueMappingTests.cs:523 in 802e4de. [](commit_id = 802e4de, deletion_comment = False)

/// Instantiates a <see cref="ColumnOptions"/> from a tuple of input and output column names.
/// </summary>
public static implicit operator ColumnOptions((string outputColumnName, string inputColumnName) value)
public InputOutputColumnPair(string outputColumnName, string inputColumnName = null)

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

outputColumnName [](start = 44, length = 16)

Check non-empty on outputColumName probably. #Resolved

/// <summary>
/// Name of the column to transform. If set to <see langword="null"/>, the value of the <see cref="OutputColumnName"/> will be used as source.
/// </summary>
public readonly string InputColumnName;

@TomFinleyTomFinleyMar 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

InputColumnName [](start = 31, length = 15)

Should these be properties? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ok making these properties!


In reply to: 268761458 [](ancestors = 268761458)

@TomFinleyTomFinley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for working on this @artidoro !! I see the central thing still isn't using properties, but I am not certain that is absolutely essential. Might be nice though if you get to it.

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

@artidoro

Copy link
Copy Markdown
ContributorAuthor

Thank you for reviewing, I am updating now with the latest changes.

@artidoro
artidoro merged commit 5f9be36 into dotnet:masterMar 25, 2019
@ghostghost locked as resolved and limited conversation to collaborators Mar 23, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@artidoro@glebuk@Ivanidzo4ka@TomFinley