From a23e6458bce37504f5d359a4b6bb881bdad99989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20B=C3=B6rchers?= Date: Thu, 9 Dec 2021 17:12:32 +0100 Subject: [PATCH] cleanup code. --- src/Helper.cs | 14 +++++++++----- src/Point.cs | 12 ++++++++++-- src/Program.cs | 34 +++++++++++++++++++--------------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/Helper.cs b/src/Helper.cs index 8e02c85..79269db 100644 --- a/src/Helper.cs +++ b/src/Helper.cs @@ -1,7 +1,7 @@ -using System.Diagnostics; +using ScottPlot; +using System.Diagnostics; using System.Drawing; using System.Globalization; -using ScottPlot; namespace kMeans; @@ -33,11 +33,9 @@ public static class Helper return plot; } - public static void ExportAndPreviewPlot(Plot plot, string path) + public static void ExportPlot(Plot plot, string path) { plot.SaveFig(path); - using var p = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); - p?.WaitForExit(); } public static IEnumerable ParseCsv(string path) @@ -51,4 +49,10 @@ public static class Helper yield return new Point(x, y, -1); } } + + public static void PreviewPlot(string path) + { + using var p = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); + p?.WaitForExit(); + } } \ No newline at end of file diff --git a/src/Point.cs b/src/Point.cs index 6bf034e..565c0c9 100644 --- a/src/Point.cs +++ b/src/Point.cs @@ -3,6 +3,14 @@ public record Point(double X, double Y, int ClusterId) { public int ClusterId { get; set; } = ClusterId; - public double X { get; set; } = X; - public double Y { get; set; } = Y; + public double X { get; private set; } = X; + public double Y { get; private set; } = Y; + + public bool SetCoordinates(double x, double y) + { + if (!(Math.Abs(X - x) > 1e-5) || !(Math.Abs(Y - y) > 1e-5)) return false; + X = x; + Y = y; + return true; + } } \ No newline at end of file diff --git a/src/Program.cs b/src/Program.cs index 2538051..4bf48c7 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -6,6 +6,7 @@ public static class Program { private const string Coordinates = "coordinates.csv"; private const int K = 3; + private const int MaxLoops = 30; private const string PlotOut = "plot.png"; public static void Main() @@ -13,19 +14,14 @@ public static class Program Console.WriteLine("k-Means-Algorithm"); var points = ParseCsv(Coordinates).ToList(); - var centroids = InitializeRandomlyCentroids(points, K).ToList(); - var update = true; - while (update) - { - AssignPointsToCentroids(points, centroids); - update = UpdateCentroids(points, centroids); - } + KMeansCalculation(points, K, out var centroids); var plot = CreatePlot(points, centroids); - ExportAndPreviewPlot(plot, PlotOut); + ExportPlot(plot, PlotOut); + PreviewPlot(PlotOut); } - private static void AssignPointsToCentroids(List points, List centroids) + private static void AssignPointsToCentroids(IEnumerable points, IReadOnlyCollection centroids) { foreach (var point in points) { @@ -49,7 +45,7 @@ public static class Program return Math.Sqrt(Math.Pow(centroid.X - point.X, 2) + Math.Pow(centroid.Y - point.Y, 2)); } - private static IEnumerable InitializeRandomlyCentroids(IReadOnlyCollection points, int k) + private static IEnumerable InitializeRandomCentroids(IReadOnlyCollection points, int k) { var minX = points.Min(p => p.X); var maxX = points.Max(p => p.X); @@ -67,7 +63,18 @@ public static class Program } } - private static bool UpdateCentroids(IReadOnlyCollection points, List centroids) + private static void KMeansCalculation(IReadOnlyCollection points, int k, out IReadOnlyCollection centroids) + { + centroids = InitializeRandomCentroids(points, k).ToArray(); + + for (var i = 0; i < MaxLoops; i++) + { + AssignPointsToCentroids(points, centroids); + if (!UpdateCentroids(points, centroids)) break; + } + } + + private static bool UpdateCentroids(IReadOnlyCollection points, IEnumerable centroids) { // calculate mean of all points of one cluster. var updated = false; @@ -87,9 +94,6 @@ public static class Program var sumY = pointsOfCluster.Sum(p => p.Y); var meanY = sumY / pointsOfCluster.Length; - if (!(Math.Abs(centroid.X - meanX) > 1e-5) || !(Math.Abs(centroid.Y - meanY) > 1e-5)) return false; - centroid.X = meanX; - centroid.Y = meanY; - return true; + return centroid.SetCoordinates(meanX, meanY); } } \ No newline at end of file