How to insert the column to predict (label) - c#

I am building a multiclass classification program and i want to dynamicaly insert train data from a CSV.
I have tried:
var loader = context.Data.CreateTextLoader(
new[]
{
new TextLoader.Column("sentiment", DataKind.String,0),
new TextLoader.Column("content", DataKind.String, 1),
},
// First line of the file is a header, not a data row.
hasHeader: true);
var trainData = loader.Load(_filePath);
var experiment = context.Auto().CreateMulticlassClassificationExperiment(240);
//find best model
var result = experiment.Execute(trainData);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Best run:");
Console.WriteLine($"Trainer name - {result.BestRun.TrainerName}");
When I run the programm I get this error
System.ArgumentException: 'Provided label column 'Label' not found in training data.'
I know there is a way to create a class on runtime and pass it as a schema in LoadFromText but I haven't been able to make it work yet.

I think I see what you need. In the Execute method, there's an overload that it can take in a ColumnInformation.
Just create an instance of that and a property on it allows you to specify the label column name.
var labelColumnInfo = new ColumnInformation()
{
LabelColumnName = "sentiment"
};
Then, you can pass that into the Execute method.
var result = experiment.Execute(trainData, labelColumnInfo);

Related

Adding records in the GAMS dotnet api have no keys

When adding records to a set, the resulting keys variable contains only one empty string, instead of the expect "i1".
var workspace = new GAMSWorkspace("TestWorkspace");
var database = workspace.AddDatabase();
var set = database.AddSet("TestSet", 1);
var record = set.AddRecord("i1");
var keys = record.Keys;
database.Export("TestDb");
What can cause this problem running the version Assembly GAMS.net4, Version=28.2.0.0
When I export the database to a .gdx file, the set contains the element i1.
How did you check, that the keysvariable does not contain the expected string? The record.Keys property returns a string[]. And if I add a WriteLine to your example, I get the expected string:
var database = ws.AddDatabase();
var set = database.AddSet("TestSet", 1);
var record = set.AddRecord("i1");
var keys = record.Keys;
Console.WriteLine(keys[0]);
Output:
i1

ML.NET: Schema mismatch for feature column 'Features'

I'm trying to learn ML.NET/Get into Machine Learning, but I'm stuck at an issue.
My goal is to create a Trained Model that can be used to predict a city based on input.
This code:
var dataPath = "cities.csv";
var mlContext = new MLContext();
var loader = mlContext.Data.CreateTextLoader<CityData>(hasHeader: false, separatorChar: ',');
var data = loader.Load(dataPath);
string featuresColumnName = "Features";
var pipeline = mlContext.Transforms.Concatenate(featuresColumnName, "PostalCode", "CityName")
.Append(mlContext.Clustering.Trainers.KMeans(featuresColumnName, clustersCount: 3));
var model = pipeline.Fit(data);
Which should take an CSV as input (Which contains a list of Cities (Column 0 = Postal Code, Column 1 = CityName), and then add these features to the pipeline, gives the following error:
Unhandled Exception: System.ArgumentOutOfRangeException: Schema mismatch for feature column 'Features': expected Vector<R4>, got Vector<Text>
On the "Fit"- function.
I've done a bit of digging on the GitHub Repo, but I can't seem to find a solution. I'm working from the Iris- example (https://learn.microsoft.com/en-us/dotnet/machine-learning/tutorials/iris-clustering) (Of course with my modifications)
Any ideas?
Using FeaturizeText to transform strings features into a float array ones
var pipeline = mlContext.Transforms
.Text.FeaturizeText("PostalCodeF", "PostalCode")
.Append(mlContext.Transforms.Text.FeaturizeText("CityNameF", "CityName"))
.Append(mlContext.Transforms.Concatenate(featuresColumnName, "PostalCodeF", "CityNameF"))
.Append(mlContext.Clustering.Trainers.KMeans(featuresColumnName, clustersCount: 3));
var model = pipeline.Fit(data);

While trying to add the value i.e. American express to the vendor field, the code is not working

List<ListOrRecordRef> List = new List<ListOrRecordRef>();
ListOrRecordRef RecordRefItem = new ListOrRecordRef();
RecordRefItem.name = "American Express";
RecordRefItem.internalId = "898";
RecordRefItem.typeId = "394";
List.Add(RecordRefItem);
rec.customFieldList = List.ToArray();
WriteResponse response = service.add(rec);
The code is used to add multiselect option of vendor. ex : american express
First of all like Heinz Siahaan said: 'List' is a keyword in C# so you can't create variable with this name.
Second:
ListOrRecordRef RecordRefItem = new ListOrRecordRef();
I'm not sure but name of this method suggest that this line of code creates list of records not one item so you can't use something like this:
RecordRefItem.name = "American Express";
but you should try :
RecordRefItem[i].name = "American Express";
where i is and index of element, but before access it you must create it
found a way its working fine://Note that for multi select option to set we have to take two class:ListOrRecordRef mention the id of the 898:American express&
//SelectCustomFieldRef to mention the field
ListOrRecordRef recordRefItem = new ListOrRecordRef();
recordRefItem.internalId = "898";
SelectCustomFieldRef scfr = new SelectCustomFieldRef();
scfr.scriptId = "custrecord_from_so_customer";
scfr.value = recordRefItem;//set the object value to the mentioned field
customFieldArray[1] = scfr;
rec.customFieldList = customFieldArray

Parse & Unity 3D : Update an existing row

Using the example code from the Unity Developer Guide | Parse
# https://www.parse.com/docs/unity_guide#objects-updating
// Create the object.
var gameScore = new ParseObject("GameScore")
{
{ "score", 1337 },
{ "playerName", "Sean Plott" },
{ "cheatMode", false },
{ "skills", new List<string> { "pwnage", "flying" } },
};
gameScore.SaveAsync().ContinueWith(t =>
{
// Now let's update it with some new data. In this case, only cheatMode
// and score will get sent to the cloud. playerName hasn't changed.
gameScore["cheatMode"] = true;
It just adds a new row and leaves the original row unchanged.
I guess i'm thinking Parse would do something "SQL like" such as UPDATE where primaryKey = 123.
Searching for an answer i found this code #
https://parse.com/questions/updating-a-field-without-retrieving-the-object-first, but there was no example in C#. All attempts to port this to C# result in multiple syntax errors.
UnityScript:
// Create a pointer to an object of class Point with id dlkj83d
var Point = Parse.Object.extend("Point");
var point = new Point();
point.id = "dlkj83d";
// Set a new value on quantity
point.set("quantity", 6);
// Save
point.save(null, {
success: function(point) {
// Saved successfully.
},
error: function(point, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
}
});
Does Parse have some way to update a row that already exists using C#? And where is it in the docs? And how can their own example be so useless?
One of the posts related to my question stated "retrieve the object, then write it back with the changes" and i had not the faintest idea how to execute the stated objective (especially after the epic fail of Parse Documentation's example code)
Here is what i have been able to figure out and make work:
var query = new ParseQuery<ParseObject>("Tokens")
.WhereEqualTo ("objectId", "XC18riofu9");
query.FindAsync().ContinueWith(t =>
{
var tokens = t.Result;
IEnumerator<ParseObject> enumerator = tokens.GetEnumerator();
enumerator.MoveNext();
var token = enumerator.Current;
token["power"] = 20;
return token.SaveAsync();
}).Unwrap().ContinueWith(t =>
{
// Everything is done!
//Debug.Log("Token has been updated!");
});
the first part retrieves the object with the stated objectId, the second part sets the fields in the object. The third part reports all is well with the operation.
it's a monkey see, monkey do understanding at this point being that i do not understand the finer points in the code.
the code can be tested by creating a class named "Tokens". in that class create a tokenName field and a power field. make a few rows with Fire, water, mud as the tokenNames. Replace the objectId in the .WhereEqualTo clause with a valid objectId or any other search parameters you like. Execute the code and observe the changes in the Parse Data Browser.
For extra credit create the class required to implement the example code from the Chaining Tasks Together section of Parse's Documentation.
https://www.parse.com/docs/unity_guide#tasks-chaining

Using Accord.Net's Codification Object to Codify second data set

I am trying to figure out how to use the Accord.Net Framework to make a bayesian prediction using the machine learning NaiveBayes class. I have followed the example code listed in the documentation and have been able to create the model from the example.
What I can't figure out is how to make a prediction based on that model.
The way the Accord.Net framework works is that it translates a table of strings into numeric symolic representation of those strings using a class called Codification. Here is how I create inputs and outputs DataTable to train the model (90% of this code is straight from the example):
var dt = new DataTable("Categorizer");
dt.Columns.Add("Word");
dt.Columns.Add("Category");
foreach (string category in categories)
{
rep.LoadTrainingDataForCategory(category,dt);
}
var codebook = new Codification(dt);
DataTable symbols = codebook.Apply(dt);
double[][] inputs = symbols.ToArray("Word");
int[] outputs = symbols.ToIntArray("Category").GetColumn(0);
IUnivariateDistribution[] priors = {new GeneralDiscreteDistribution(codebook["Word"].Symbols)};
int inputCount = 1;
int classCount = codebook["Category"].Symbols;
var target = new NaiveBayes<IUnivariateDistribution>(classCount, inputCount, priors);
target.Estimate(inputs, outputs);
And this all works successfully. Now, I have new input that I want to test against the trained data model I just built. So I try to do this:
var testDt = new DataTable("Test Data");
testDt.Columns.Add("Word");
foreach (string token in tokens)
{
testDt.Rows.Add(token);
}
DataTable testDataSymbols = codebook.Apply(testDt);
double[] testData = testDataSymbols.ToArray("Word").GetColumn(0);
double logLikelihood = 0;
double[] responses;
int cat = target.Compute(testData, out logLikelihood, out responses);
Notice that I am using the same codebook object that I was using previously when I built the model. I want the data to be codified using the same codebook as the original model, otherwise the same word might be encoded with two completely different values (the word "bob" in the original model might correspond to the number 23 and in the new model, the number 43... no way that would work.)
However, I am getting a NullReferenceException error on this line:
DataTable testDataSymbols = codebook.Apply(testDt);
Here is the error:
System.NullReferenceException: Object reference not set to an instance of an object.
at Accord.Statistics.Filters.Codification.ProcessFilter(DataTable data)
at Accord.Statistics.Filters.BaseFilter`1.Apply(DataTable data)
at Agent.Business.BayesianClassifier.Categorize(String[] categories, String testText)
The objects I am passing in are all not null, so this must be something happening deeper in the code. But I am not sure what.
Thanks for any help. And if anyone knows of an example where a prediction is actually made from the bayesian example for Accord.Net, I would be much obliged if you shared it.
Sorry about the lack of documentation on the final part. In order to obtain the same integer codification for a new word, you could use the Translate method of the codebook:
// Compute the result for a sunny, cool, humid and windy day:
double[] input = codebook.Translate("Sunny", "Cool", "High", "Strong").ToDouble();
int answer = target.Compute(input);
string result = codebook.Translate("PlayTennis", answer); // result should be "no"
but it should also have been possible to call codebook.Apply to apply the same transformation to a new dataset. If you feel this is a bug, would you like to fill a bug report in the issue tracker?

Categories