private static void normalizePaths(List <Path> paths) { Array.Clear(normalizedPaths, 0, normalizedPaths.Count()); float maxX = -1f, maxY = -1f, maxT = -1f; float minX = Single.PositiveInfinity, minY = Single.PositiveInfinity, minT = Single.PositiveInfinity; foreach (Path p in paths) { foreach (Node n in p.points) { if (n.x > maxX) { maxX = (float)n.xD; } if (n.y > maxY) { maxY = (float)n.yD; } if (n.t > maxT) { maxT = (float)n.tD; } if (n.x < minX) { minX = (float)n.xD; } if (n.y < minY) { minY = (float)n.yD; } if (n.t < minT) { minT = (float)n.tD; } } } float maxVal = 1000f; for (int count = 0; count < paths.Count; count++) { int index = Convert.ToInt32(paths[count].name); normalizedPaths[index] = new Path(paths[count]); foreach (Node n in normalizedPaths[index].points) { n.xD = (((n.xD - minX) * maxVal) / (maxX - minX)); n.yD = (((n.yD - minY) * maxVal) / (maxY - minY)); n.tD = (((n.tD - minT) * maxVal) / (maxT - minT)); n.x = (int)n.xD; n.y = (int)n.yD; n.t = (int)n.tD; } } }
static List <Path> GetRegion(List <Path> points, Path p, double eps) { List <Path> region = new List <Path>(); for (int i = 0; i < points.Count; i++) { double dist = FindDistance(p, points[i]); if (dist <= eps) { region.Add(points[i]); } } return(region); }
public static List <PathCollection> cluster(List <Path> points, double eps, int minPts, int noise) { if (points == null) { return(null); } List <PathCollection> clusters = new List <PathCollection>(); eps *= eps; // square eps int clusterID = 1; for (int i = 0; i < points.Count; i++) { Path p = points[i]; if (p.clusterID == Path.UNCLASSIFIED) { if (ExpandCluster(points, p, clusterID, eps, minPts)) { clusterID++; } } } int maxclusterID = points.OrderBy(p => p.clusterID).Last().clusterID; if (maxclusterID < 1) { return(clusters); // no clusters, so list is empty } for (int i = 0; i < maxclusterID; i++) { clusters.Add(new PathCollection()); } foreach (Path p in points) { if (p.clusterID > 0) { clusters[p.clusterID - 1].Add(p); } } return(clusters); }
static bool ExpandCluster(List <Path> points, Path p, int clusterID, double eps, int minPts) { List <Path> seeds = GetRegion(points, p, eps); if (seeds.Count < minPts) // no core point { p.clusterID = Path.NOISE; return(false); } else // all points in seeds are density reachable from point 'p' { for (int i = 0; i < seeds.Count; i++) { seeds[i].clusterID = clusterID; } seeds.Remove(p); while (seeds.Count > 0) { Path currentP = seeds[0]; List <Path> result = GetRegion(points, currentP, eps); if (result.Count >= minPts) { for (int i = 0; i < result.Count; i++) { Path resultP = result[i]; if (resultP.clusterID == Path.UNCLASSIFIED || resultP.clusterID == Path.NOISE) { if (resultP.clusterID == Path.UNCLASSIFIED) { seeds.Add(resultP); } resultP.clusterID = clusterID; } } } seeds.Remove(currentP); } return(true); } }
public static int FindNearestCluster(List <PathCollection> allClusters, Path path) { // src : http://codeding.com/articles/k-means-algorithm double minimumDistance = 0.0; int nearestClusterIndex = -1; for (int k = 0; k < allClusters.Count; k++) //find nearest cluster { double distance = FindDistance(path, allClusters[k].Centroid); if (k == 0) { minimumDistance = distance; nearestClusterIndex = 0; } else if (minimumDistance > distance) { minimumDistance = distance; nearestClusterIndex = k; } } return(nearestClusterIndex); }
public static double FindDistance(Path path1_, Path path2_) { if (path1_.points == null) { Console.WriteLine(("P1NULL")); return(-1); } ////{ Debug.Log("P1NULL"); return -1; } else if (path2_.points == null) { Console.WriteLine(("P2NULL")); return(-1); } ////{ Debug.Log("P2NULL"); return -1; } int p1num = Convert.ToInt32(path1_.name); int p2num = Convert.ToInt32(path2_.name); if (path1_.name == path2_.name) { // same path return(0.0); } Path path1, path2; bool saveDistances = false; if (p1num <= Clustering.distances.Count() && p2num <= Clustering.distances.Count()) { if (Clustering.distances[p1num][p2num] != -1) { return(Clustering.distances[p1num][p2num]); } if (Clustering.distances[p2num][p1num] != -1) { return(Clustering.distances[p2num][p1num]); } path1 = Clustering.normalizedPaths[p1num]; path2 = Clustering.normalizedPaths[p2num]; saveDistances = true; } else { Console.WriteLine("Note - not storing this distance."); ////Debug.Log("Note - not storing this distance."); path1 = path1_; path2 = path2_; } double result = 0.0; if (distMetric == (int)Metrics.Frechet || distMetric == (int)Metrics.Hausdorff) { double[][] curveA = new double[path1.points.Count][]; double[][] curveB = new double[path2.points.Count][]; for (int i = 0; i < path1.points.Count; i++) { double[] curve = new double[numSelectedDimensions]; int curvePos = 0; for (int j = 0; j < dimensionEnabled.Count(); j++) { if (dimensionEnabled[j]) { if (j == (int)Dimensions.X) { curve[curvePos] = path1.points[i].xD; } else if (j == (int)Dimensions.Y) { curve[curvePos] = path1.points[i].yD; } else if (j == (int)Dimensions.Time) { curve[curvePos] = path1.points[i].tD; } curvePos++; } } curveA[i] = curve; } for (int i = 0; i < path2.points.Count; i++) { double[] curve = new double[numSelectedDimensions]; int curvePos = 0; for (int j = 0; j < dimensionEnabled.Count(); j++) { if (dimensionEnabled[j]) { if (j == (int)Dimensions.X) { curve[curvePos] = path2.points[i].xD; } else if (j == (int)Dimensions.Y) { curve[curvePos] = path2.points[i].yD; } else if (j == (int)Dimensions.Time) { curve[curvePos] = path2.points[i].tD; } curvePos++; } } curveB[i] = curve; } if (distMetric == (int)Metrics.Frechet) { result = frechet.computeDistance(curveA, curveB); } } else { Console.WriteLine("Invalid distance metric (" + distMetric + ")!"); ////Debug.Log("Invalid distance metric ("+distMetric+")!"); return(-1); } if (saveDistances) { Clustering.distances[p1num][p2num] = result; Clustering.distances[p2num][p1num] = result; } return(result); }
public static double FindDistance(Path path1, Path path2, int distMetric_) { setDistMetric(distMetric_); return(FindDistance(path1, path2)); }
public static List <PathCollection> cluster(List <PathCollection> allClusters, double[] weights_) { // based on http://codeding.com/articles/k-means-algorithm for (int i = 0; i < allClusters.Count(); i++) { if (allClusters[i].Count() == 0) { Console.WriteLine("Empty cluster, #" + i); } } weights = weights_; int movements = 1; int count = 0; int[] previousMovements = new int[100]; while (movements > 0) { Console.WriteLine(count); previousMovements[count] = movements; if (count > 25) { int avgLastThree = (previousMovements[count - 2] + previousMovements[count - 1] + previousMovements[count]) / 3; if (Math.Abs(avgLastThree - previousMovements[count]) <= 10) { Console.WriteLine("Not converging."); break; } } count++; movements = 0; for (int clusterIndex = 0; clusterIndex < allClusters.Count; clusterIndex++) { for (int pathIndex = 0; pathIndex < allClusters[clusterIndex].Count; pathIndex++) //for all paths in each cluster { Path path = allClusters[clusterIndex][pathIndex]; int nearestCluster = FindNearestCluster(allClusters, path); if (nearestCluster != clusterIndex) //if path has moved { if (allClusters[clusterIndex].Count > 1) //cluster shall have minimum one path { Path removedPath = allClusters[clusterIndex].RemovePath(path); allClusters[nearestCluster].AddPath(removedPath); movements += 1; } } } } foreach (PathCollection cluster in allClusters) { if (cluster.changed) { cluster.UpdateCentroid(clustAlg); movements += 1; cluster.changed = false; } } } return(allClusters); }
public static List <PathCollection> DoKMeans(List <Path> paths, int clusterCount, int distMetric_, int numPasses, double[] weights) { if (paths.Count == 0) { Console.WriteLine("No paths to cluster!"); return(null); } setDistMetric(distMetric_); clustTime.Start(); double bestE = double.MaxValue; List <PathCollection> bestClustering = new List <PathCollection>(); for (int curPass = 0; curPass < numPasses; curPass++) { Console.WriteLine("Pass " + curPass); List <PathCollection> allClusters = new List <PathCollection>(); if (useScalable) { allClusters = cluster(initializeCentroidsScalable(paths, clusterCount), KMeans.weights); } else { allClusters = cluster(initializeCentroids(paths, clusterCount, weights), weights); } // get, for each cluster, the average distance of all elements in that cluster to the cluster centroid Path[] averageCentroids = new Path[allClusters.Count()]; for (int i = 0; i < allClusters.Count(); i++) { averageCentroids[i] = allClusters[i].getAveragedCentroid(); int newIndex = paths.Count() + 1000 + i; averageCentroids[i].name = newIndex.ToString(); } double[] avgDists = new double[allClusters.Count()]; for (int i = 0; i < allClusters.Count(); i++) { avgDists[i] = 0.0; foreach (Path p in allClusters[i]) { avgDists[i] += FindDistance(p, averageCentroids[i]); } } double sumMaxVals = 0.0; for (int i = 0; i < allClusters.Count(); i++) { // sum over all clusters double maxVal = 0.0; for (int j = 0; j < allClusters.Count(); j++) { if (i == j) { continue; } double distBetweenCentroids = FindDistance(averageCentroids[i], averageCentroids[j]); double clustVal = 0.0; if (avgDists[i] + avgDists[j] != 0.0) { clustVal = (avgDists[i] + avgDists[j]) / distBetweenCentroids; } if (Double.IsInfinity(clustVal)) { clustVal = 10000.0; } if (clustVal > maxVal) { maxVal = clustVal; } } sumMaxVals += maxVal; } double clusteringQuality = sumMaxVals / allClusters.Count(); // sum * 1/n Console.WriteLine("Pass " + curPass + ", DB val: " + clusteringQuality); if (clusteringQuality <= 0) { Console.WriteLine("Something has gone horribly wrong."); } else if (clusteringQuality < bestE || curPass == 0) { bestE = clusteringQuality; clustVal = bestE; bestClustering.Clear(); foreach (PathCollection c in allClusters) { bestClustering.Add(c); } } } clustTime.Stop(); return(bestClustering); }