Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh
, '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

Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh
, '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

Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh
, '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

Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh
, '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

Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh
, '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

Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh
, '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

Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh
, '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

Add in ability to have pre-defined weights for ngrams. - #6458

Merged
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram
Nov 23, 2022
Merged

Add in ability to have pre-defined weights for ngrams.#6458
michaelgsharp merged 5 commits into
dotnet:mainfrom
michaelgsharp:ngram

Conversation

@michaelgsharp

Copy link
Copy Markdown
Contributor

Add in ability to have pre-defined weights for ngrams.

@michaelgsharp
michaelgsharp requested a review from a teamNovember 17, 2022 20:49
@michaelgsharpmichaelgsharp self-assigned this Nov 17, 2022
@codecov

codecovBot commented Nov 17, 2022

Copy link
Copy Markdown

Codecov Report

Merging #6458 (61044f5) into main (17c061a) will decrease coverage by 0.03%.
The diff coverage is 95.21%.

Additional details and impacted files
@@ Coverage Diff @@## main #6458 +/- ##
==========================================
- Coverage 68.55% 68.51% -0.04% 
==========================================
Files 1170 1171 +1 Lines 246977 247159 +182 Branches 25792 25798 +6 ==========================================
+ Hits 169304 169337 +33 - Misses 70950 71079 +129 - Partials 6723 6743 +20 
FlagCoverage Δ
Debug68.51% <95.21%> (-0.04%)⬇️
production62.89% <92.98%> (-0.06%)⬇️
test88.97% <98.64%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted FilesCoverage Δ
...c/Microsoft.ML.Transforms/Text/WordBagTransform.cs82.50% <92.15%> (+3.90%)⬆️
...t.ML.Tests/Transformers/WordBagTransformerTests.cs98.64% <98.64%> (ø)
src/Microsoft.ML.Transforms/Text/TextCatalog.cs68.62% <100.00%> (+1.28%)⬆️
...soft.ML.Transforms/Text/WrappedTextTransformers.cs99.15% <100.00%> (+0.04%)⬆️
...osoft.ML.KMeansClustering/KMeansPlusPlusTrainer.cs83.92% <0.00%> (-7.16%)⬇️
src/Microsoft.ML.FastTree/Training/StepSearch.cs57.42% <0.00%> (-4.96%)⬇️
src/Microsoft.ML.Data/Training/TrainerUtils.cs66.26% <0.00%> (-3.82%)⬇️
...crosoft.ML.StandardTrainers/Standard/SdcaBinary.cs85.40% <0.00%> (-3.42%)⬇️
src/Microsoft.ML.Sweeper/AsyncSweeper.cs71.42% <0.00%> (-1.37%)⬇️
...oft.ML.StandardTrainers/Standard/SdcaMulticlass.cs91.46% <0.00%> (-1.03%)⬇️
... and 3 more

/// <param name="termSeparator">Separator used to separate terms/frequency pairs.</param>
/// <param name="freqSeparator">Separator used to separate terms from their frequency.</param>
/// This estimator operates over vector of text.</param>
public static WordBagEstimator ProduceWordBagsPreDefinedWeight(this TransformsCatalog.TextTransforms catalog,

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.

@ericstj@luisquintanilla@tannergooding thoughts on this api name? The normal one is just called ProduceWordBags, but when naming this one that it can potentially cause ambiguity issues due to the default parameters not needing to be specified.

I had 2 options, either name it something different, or not have default parameters and make the users specify the term separator and frequency separator manually each time. I went with the first approach, but want to hear your opinions on it.

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.

@tarekgh your thoughts as well if you have time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My thoughts:

In main scenarios is it expected to be called once or twice in the code? If yes, then I prefer using ProduceWordBags without any optional parameter. Will be just overload. If the answer is no, then using a different name would be better, I guess. We may try to suggest a better name than ProduceWordBagsPreDefinedWeight. May be ``ProduceWordBagsEstimator` is simpler?

@bartonjsbartonjsNov 18, 2022

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With the current name, I think a "With" should be in there (ProduceWordBagsWithPreDefinedWeight). Though since the caller doesn't get to specify it "PreDefined" seems more like "Default".

I assume the real reason a caller wants this method is to specify the term and/or freq separators. Can this not just be added as a true extra optional parameter overload using the established patterns?

+ [EditorBrowsable(EditorBrowsableState.Never)]
public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,
string outputColumnName,
string inputColumnName = null,
- int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int ngramLength,- int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ int skipLength,- bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ bool useAllLengths,- int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ int maximumNgramsCount,- NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf)+ NgramExtractingEstimator.WeightingCriteria weighting)
=> new WordBagEstimator(Contracts.CheckRef(catalog, nameof(catalog)).GetEnvironment(),
outputColumnName, inputColumnName, ngramLength, skipLength, useAllLengths, maximumNgramsCount, weighting);
+ public static WordBagEstimator ProduceWordBags(this TransformsCatalog.TextTransforms catalog,+ string outputColumnName,+ string inputColumnName = null,+ int ngramLength = NgramExtractingEstimator.Defaults.NgramLength,+ int skipLength = NgramExtractingEstimator.Defaults.SkipLength,+ bool useAllLengths = NgramExtractingEstimator.Defaults.UseAllLengths,+ int maximumNgramsCount = NgramExtractingEstimator.Defaults.MaximumNgramsCount,+ NgramExtractingEstimator.WeightingCriteria weighting = NgramExtractingEstimator.WeightingCriteria.Tf,+ char termSeparator = ';',+ char freqSeparator = ':')+ => new WordBagEstimator(parameters go here);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Which overload will be chosen if the caller is passing only the first parameter?

If the compiled in the past, the old one. If they compile after, the new one. (The old method, now marked as [EB(Never)] is only called by a) legacy callers or b) someone who happened to specify all of those parameters and none of the new ones... the compiler will still (and only) call it if the callsite has an exact match to the signature.

Since both methods are creating a WordBagEstimator I'm assuming that "specifying the weighting" and "specifying the freq/term-separator" aren't actually conflicting options. If they are conflicting options, then some sort of differentiated name is warranted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would changing the existing method though by adding new default parameters count as a breaking change @ericstj?

Adding the parameters to the existing method is a breaking change (a really, really bad one). Adding it the way I suggested is the way to make it look like all you did was add new default parameters.

From Framework Design Guidelines, 3rd edition, sec 5.1 (General Member Design Guidelines):

DO move all default parameters to the new, longer overload when adding optional parameters to an existing method.

[prose that says to do what I said to do above]

and down in Appendix D (breaking changes) (emphasis mine):

D.11.2 Adding or Removing a Method Parameter

Methods in the .NET CLR are identified by their signature, which is composed
of the name, return type, and ordered list of parameters. Removing
a parameter, adding a required parameter, or adding an optional parameter
all count as changing the signature and, therefore, are logically the
same as deleting the original method. See section D.9.3 for information on
the runtime impact of removing a member.

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.

@bartonjs the separators and the weight aren't conflicting options. The default should be just to use the frequency of the words, but there isn't a problem if they are both specified together (though I would bet that most people don't want to specify both together and probably would give them unexpected, though not incorrect, behavior if they do that).

I think making the name the same with a new overload where the user has to specify the separators is probably the best based on this convo. We don't want the separators specified unless the user really needs them, since thats the flag that tells word bag that it needs to handle the input data differently.

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.

@bartonjs I have made the changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That new catalog overload looks a lot nicer to me 😄

@michaelgsharp
michaelgsharp merged commit bb563da into dotnet:mainNov 23, 2022
@michaelgsharp
michaelgsharp deleted the ngram branch November 23, 2022 06:11
michaelgsharp added a commit to michaelgsharp/machinelearning that referenced this pull request Nov 23, 2022
Merging on red since it was approved but approver doesn't have write access.
@ghostghost locked as resolved and limited conversation to collaborators Dec 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.

3 participants

@michaelgsharp@bartonjs@tarekgh