diff --git a/machine-learning/tutorials/IrisFlowerClustering.sln b/machine-learning/tutorials/IrisFlowerClustering.sln
new file mode 100644
index 00000000000..af6929a9d9b
--- /dev/null
+++ b/machine-learning/tutorials/IrisFlowerClustering.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.168
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IrisFlowerClustering", "IrisFlowerClustering\IrisFlowerClustering.csproj", "{B1297D9B-46A6-4A03-A04E-65B2FAC0B687}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B1297D9B-46A6-4A03-A04E-65B2FAC0B687}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1297D9B-46A6-4A03-A04E-65B2FAC0B687}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1297D9B-46A6-4A03-A04E-65B2FAC0B687}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1297D9B-46A6-4A03-A04E-65B2FAC0B687}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {30D318E3-A018-46F2-8D53-F72211D6BA70}
+ EndGlobalSection
+EndGlobal
diff --git a/machine-learning/tutorials/IrisFlowerClustering/IrisData.cs b/machine-learning/tutorials/IrisFlowerClustering/IrisData.cs
new file mode 100644
index 00000000000..e6c5691f6dc
--- /dev/null
+++ b/machine-learning/tutorials/IrisFlowerClustering/IrisData.cs
@@ -0,0 +1,32 @@
+//
+using Microsoft.ML.Runtime.Api;
+//
+
+namespace IrisFlowerClustering
+{
+ //
+ public class IrisData
+ {
+ [Column("0")]
+ public float SepalLength;
+
+ [Column("1")]
+ public float SepalWidth;
+
+ [Column("2")]
+ public float PetalLength;
+
+ [Column("3")]
+ public float PetalWidth;
+ }
+
+ public class ClusterPrediction
+ {
+ [ColumnName("PredictedLabel")]
+ public uint PredictedClusterId;
+
+ [ColumnName("Score")]
+ public float[] Distances;
+ }
+ //
+}
diff --git a/machine-learning/tutorials/IrisFlowerClustering/IrisFlowerClustering.csproj b/machine-learning/tutorials/IrisFlowerClustering/IrisFlowerClustering.csproj
new file mode 100644
index 00000000000..476708f04d5
--- /dev/null
+++ b/machine-learning/tutorials/IrisFlowerClustering/IrisFlowerClustering.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ netcoreapp2.2
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/machine-learning/tutorials/IrisFlowerClustering/Program.cs b/machine-learning/tutorials/IrisFlowerClustering/Program.cs
new file mode 100644
index 00000000000..c3b8bb535ce
--- /dev/null
+++ b/machine-learning/tutorials/IrisFlowerClustering/Program.cs
@@ -0,0 +1,74 @@
+//
+using System;
+using System.IO;
+//
+
+//
+using Microsoft.ML;
+using Microsoft.ML.Runtime.Data;
+//
+
+namespace IrisFlowerClustering
+{
+ class Program
+ {
+ //
+ static readonly string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "iris.data");
+ static readonly string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "IrisClusteringModel.zip");
+ //
+
+ static void Main(string[] args)
+ {
+ //
+ var mlContext = new MLContext(seed: 0);
+ //
+
+ //
+ TextLoader textLoader = mlContext.Data.TextReader(new TextLoader.Arguments()
+ {
+ Separator = ",",
+ HasHeader = false,
+ Column = new[]
+ {
+ new TextLoader.Column("SepalLength", DataKind.R4, 0),
+ new TextLoader.Column("SepalWidth", DataKind.R4, 1),
+ new TextLoader.Column("PetalLength", DataKind.R4, 2),
+ new TextLoader.Column("PetalWidth", DataKind.R4, 3)
+ }
+ });
+ //
+
+ //
+ IDataView dataView = textLoader.Read(_dataPath);
+ //
+
+ //
+ string featuresColumnName = "Features";
+ var pipeline = mlContext.Transforms
+ .Concatenate(featuresColumnName, "SepalLength", "SepalWidth", "PetalLength", "PetalWidth")
+ .Append(mlContext.Clustering.Trainers.KMeans(featuresColumnName, clustersCount: 3));
+ //
+
+ //
+ var model = pipeline.Fit(dataView);
+ //
+
+ //
+ using (var fileStream = new FileStream(_modelPath, FileMode.Create, FileAccess.Write, FileShare.Write))
+ {
+ mlContext.Model.Save(model, fileStream);
+ }
+ //
+
+ //
+ var predictor = model.MakePredictionFunction(mlContext);
+ //
+
+ //
+ var prediction = predictor.Predict(TestIrisData.Setosa);
+ Console.WriteLine($"Cluster: {prediction.PredictedClusterId}");
+ Console.WriteLine($"Distances: {string.Join(" ", prediction.Distances)}");
+ //
+ }
+ }
+}
diff --git a/machine-learning/tutorials/IrisFlowerClustering/TestIrisData.cs b/machine-learning/tutorials/IrisFlowerClustering/TestIrisData.cs
new file mode 100644
index 00000000000..4fd2c66fc21
--- /dev/null
+++ b/machine-learning/tutorials/IrisFlowerClustering/TestIrisData.cs
@@ -0,0 +1,17 @@
+namespace IrisFlowerClustering
+{
+ //
+ static class TestIrisData
+ //
+ {
+ //
+ internal static readonly IrisData Setosa = new IrisData
+ {
+ SepalLength = 5.1f,
+ SepalWidth = 3.5f,
+ PetalLength = 1.4f,
+ PetalWidth = 0.2f
+ };
+ //
+ }
+}