private void MixMatch(string dataPath) { // Create a new context for ML.NET operations. It can be used for exception tracking and logging, // as a catalog of available operations and as the source of randomness. var mlContext = new MLContext(); // Read the data as an IDataView. // First, we define the loader: specify the data columns and where to find them in the text file. var loader = mlContext.Data.CreateTextLoader(ctx => ( // The four features of the Iris dataset. SepalLength: ctx.LoadFloat(0), SepalWidth: ctx.LoadFloat(1), PetalLength: ctx.LoadFloat(2), PetalWidth: ctx.LoadFloat(3), // Label: kind of iris. Label: ctx.LoadText(4) ), // Default separator is tab, but the dataset has comma. separator: ','); // Read the data. var data = loader.Load(dataPath); // Build the pre-processing pipeline. var pipeline = loader.MakeNewEstimator() .Append(r => ( // Convert string label to a key. Label: r.Label.ToKey(), // Concatenate all the features together into one column 'Features'. Features: r.SepalLength.ConcatWith(r.SepalWidth, r.PetalLength, r.PetalWidth))); // Now, at the time of writing, there is no static pipeline for OVA (one-versus-all). So, let's // append the OVA learner to the dynamic pipeline. IEstimator <ITransformer> dynamicPipe = pipeline.AsDynamic; // Create a binary classification trainer. var binaryTrainer = mlContext.BinaryClassification.Trainers.AveragedPerceptron("Label", "Features"); // Append the OVA learner to the pipeline. dynamicPipe = dynamicPipe.Append(mlContext.MulticlassClassification.Trainers.OneVersusAll(binaryTrainer)); // At this point, we have a choice. We could continue working with the dynamically-typed pipeline, and // ultimately call dynamicPipe.Fit(data.AsDynamic) to get the model, or we could go back into the static world. // Here's how we go back to the static pipeline: var staticFinalPipe = dynamicPipe.AssertStatic(mlContext, // Declare the shape of the input. As you can see, it's identical to the shape of the loader: // four float features and a string label. c => ( SepalLength: c.R4.Scalar, SepalWidth: c.R4.Scalar, PetalLength: c.R4.Scalar, PetalWidth: c.R4.Scalar, Label: c.Text.Scalar), // Declare the shape of the output (or a relevant subset of it). // In our case, we care only about the predicted label column (a key type), and scores (vector of floats). c => ( Score: c.R4.Vector, // Predicted label is a key backed by uint, with text values (since original labels are text). PredictedLabel: c.KeyU4.TextValues.Scalar)) // Convert the predicted label from key back to the original string value. .Append(r => r.PredictedLabel.ToValue()); // Train the model in a statically typed way. var model = staticFinalPipe.Fit(data); // And here is how we could've stayed in the dynamic pipeline and train that way. dynamicPipe = dynamicPipe.Append(new KeyToValueMappingEstimator(mlContext, "PredictedLabel")); var dynamicModel = dynamicPipe.Fit(data.AsDynamic); // Now 'dynamicModel', and 'model.AsDynamic' are equivalent. }