Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka
, '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

Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka
, '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

Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka
, '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

Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka
, '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

Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka
, '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

Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka
, '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

Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka
, '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

Clean up of TextLoader constructor - #1784

Merged
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader
Dec 7, 2018
Merged

Clean up of TextLoader constructor#1784
artidoro merged 9 commits into
dotnet:masterfrom
artidoro:textloader

Conversation

@artidoro

Copy link
Copy Markdown
Contributor

Fixes#1611.

  1. Hid the constructor of TextLoader that takes Arguments, and exposed HasHeader and SeparatorChars as non-advanced parameters.
  2. Made Create methods internal and modified the code accordingly.
  3. Added comments for the public facing constructor that was retained.

/// <param name="env">The environment to use.</param>
/// <param name="columns">Defines a mapping between input columns in the file and IDataView columns.</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChars">Defines the characters used as separators between data points in a row. By default the tab character is taken as separator.</param>

@Ivanidzo4kaIvanidzo4kaNov 29, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

By default the tab character [](start = 112, length = 29)

this statement and char[] separatorChars = null a bit weird.
I know what latter down the line we probably check for null in separators, and use tab as default, but still. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes it is not ideal, that's why I have an explanation in the documentation above. But if you have a better idea, I would be happy to take it!


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

},
// First line of the file is a header, not a data row.
HasHeader = true,
true,

@eerhardteerhardtNov 30, 2018

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.

I'd still qualify hasHeader: here. #Resolved

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.

Apply this everywhere - especially in docs/samples/etc.


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

// Default separator is tab, but we need a semicolon.
Separator = ";"
});
new[] { ';' }

@eerhardteerhardtNov 30, 2018

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.

Isn't the single separator the more common case? Maybe the "simple" constructor just takes a single character separator. And the "advanced" case can support multiple separators. #Resolved

/// <param name="catalog">The catalog.</param>
/// <param name="args">The arguments to text reader, describing the data schema.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtNov 30, 2018

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.

Yesterday in the API design review, we decided against this approach. See the notes from the review here: https://github.com/dotnet/apireviews/pull/81/files

But basically, the pattern decided will be:

  1. Make a simple constructor/factory that has the most common parameters.
  2. If there are advanced parameters that we don't want exposed in Get a working build #1, then make another constructor/factory that takes the only the nested Arguments class (to be renamed to "Options").

We are going to move away from the Action<Arguments> advancedSettings approach. One main reason is because there can be conflicts between the "simple" parameters and the "advanced" parameters - and which one should win? Another reasoning is that it is simpler and understandable to construct and pass an object to a method.

I'd say, for this change, let's not move away from where we are going. You don't need to rename Arguments to Options. But let's leave this overload, and remove the "advancedSettings" parameter below instead. #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I have left the overload as you suggested and removed the advanced arguments parameter from the constructors.


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

@artidoro

artidoro commented Nov 30, 2018

Copy link
Copy Markdown
ContributorAuthor

Thanks @eerhardt! I'll update accordingly #Resolved

@eerhardt

eerhardt commented Nov 30, 2018

Copy link
Copy Markdown
Member

Sorry for the "late breaking" change here, but I thought it would be good to note where we landed yesterday, and not have to redo some of this work. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am doing the changes and it looks a lot better, it's good to see that!


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

/// <param name="advancedSettings">The delegate to set additional settings</param>
/// <param name="path">The path to the file</param>
/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[](start = 40, length = 1)

extra space, here and in constructor above. #Resolved


var env = catalog.GetEnvironment();

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here.

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

// REVIEW: it is almost always a mistake to have a 'trainable' text loader here [](start = 12, length = 79)

Did it work well if you specify header to true and didn't pass dataSample? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, check this test public void CustomTransformer()


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

// ignoring this stream if it isn't as expected.
var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = TextLoader.ReadFile(env, new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

, new TextLoader.Arguments() [](start = 120, length = 28)

can we change method to have arg default = null, and if it's null to use new TextLoader.Arguments()? #Resolved

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Sure, I can do that. Do you think I should change that in the constructor of TextLoader too?


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

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.

Yes I think it makes sense


In reply to: 239258487 [](ancestors = 239258487,239162303)

// Pipeline
var loader = TextLoader.ReadFile(env,
new TextLoader.Arguments()
var arguemnts = new TextLoader.Arguments()

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

arguemnts [](start = 16, length = 9)

msitype #Resolved

@@ -369,7 +364,11 @@ private static IComponentFactory<IMultiStreamSource, IDataLoader> GetLoaderFacto
var txtArgs = new TextLoader.Arguments();
bool parsed = CmdParser.ParseArguments(host, "col=Term:TX:0 col=Value:TX:1", txtArgs);

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need this anymore #Resolved

{
var dataPath = GetDataPath("breast-cancer.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

can you use ReadTextFile instead? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

{
var dataPath = GetDataPath("adult.tiny.with-schema.txt");
var dataView = TextLoader.Create(Env, new TextLoader.Arguments(), new MultiFileSource(dataPath));
var dataView = TextLoader.ReadFile(Env, new MultiFileSource(dataPath), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 38, length = 8)

ReadTextFile #ByDesign

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

across whole file


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

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

// Note that we don't pass in "args", but pass in a default args so we test
// the auto-schema parsing.
var loadedData = TextLoader.ReadFile(env, new TextLoader.Arguments(), new MultiFileSource(pathData));
var loadedData = TextLoader.ReadFile(env, new MultiFileSource(pathData), new TextLoader.Arguments());

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ReadFile [](start = 40, length = 8)

ReadTextFile? #ByDesign

@eerhardteerhardtDec 5, 2018

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.

Isn't text implied by the name of TextLoader? #Resolved

@artidoroartidoroDec 5, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I agree with Eric, since it's a method of TextLoader it should already implied that it loads a text file. #Resolved

var reader = mlContext.Data.TextReader(new TextLoader.Arguments
{
Column = new[] {
var reader = mlContext.Data.TextReader(new[] {

@Ivanidzo4kaIvanidzo4kaDec 5, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TextReader [](start = 40, length = 10)

please update https://github.com/dotnet/machinelearning/blob/master/docs/code/MlNetCookBook.md with your changes. #Resolved

@Ivanidzo4kaIvanidzo4ka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar">The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="dataSample">The optional location of a data sample.</param>
public static TextLoader TextReader(this DataOperations catalog,

@eerhardteerhardtDec 6, 2018

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.

I think we want these named CreateTextReader. See https://github.com/dotnet/apireviews/pull/81/files #Resolved

/// <param name="hasHeader">Whether the file has a header.</param>
/// <param name="separatorChar"> The character used as separator between data points in a row. By default the tab character is used as separator.</param>
/// <param name="fileSource">Specifies a file from which to read.</param>
public static IDataView ReadFile(IHostEnvironment env, IMultiStreamSource fileSource, Column[] columns, bool hasHeader = false, char separatorChar = '\t')

@eerhardteerhardtDec 6, 2018

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.

Why do we have both IDataView ReadFromTextFile(this DataOperations catalog, and these methods? I think we should only have 1. #Resolved

@artidoro

artidoro commented Dec 6, 2018

Copy link
Copy Markdown
ContributorAuthor

@eerhardt I just removed the ReadFile method from TextLoader, as you suggested. #Resolved

@artidoro

Copy link
Copy Markdown
ContributorAuthor

I am actually updating the cookbook again, to reflect that and the new name for the MlContext extension.


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

{
var result = new Arguments { Column = columns };
advancedSettings?.Invoke(result);
separatorChars = separatorChars ?? new[] { '\t' };

@eerhardteerhardtDec 7, 2018

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.

(nit) separatorChars can never be null, right? This is a private method and only called in 1 spot that ensures it won't be null.

Maybe just add an Assert it won't be null and you can remove the null check here. #Resolved

var loader = TextLoader.ReadFile(env, new TextLoader.Arguments(),
new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));
var loader = new TextLoader(env, dataSample: new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile))
.Read(new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile));

@eerhardteerhardtDec 7, 2018

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.

We shouldn't create two instances of new RepositoryStreamWrapper(rep, DirTrainingInfo, RoleMappingFile). #Resolved

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.

Maybe it may be valuable to still have an internal TextLoader.ReadFile helper method for our internal code.


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

new TextLoader.Column("Term", DataKind.TX, 0),
new TextLoader.Column("Value", DataKind.TX, 1)
},
dataSample: new MultiFileSource(filename)

@eerhardteerhardtDec 7, 2018

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.

Same comment here about creating duplicate objects - new MultiFileSource(filename) #Resolved

@eerhardteerhardt left a comment

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.

Looks good. Just a couple minor comments to clean up.

@artidoroartidoro self-assigned this Dec 7, 2018
@artidoroartidoro added the API Issues pertaining the friendly API label Dec 7, 2018
@artidoro
artidoro merged commit 14c7a47 into dotnet:masterDec 7, 2018
@artidoro
artidoro deleted the textloader branch January 5, 2019 00:01
@ghostghost locked as resolved and limited conversation to collaborators Mar 26, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

APIIssues pertaining the friendly API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@artidoro@eerhardt@Ivanidzo4ka