/// <summary> /// Measures distance between two points /// </summary> public static double Dist(ClusterGame x, ClusterGame y) { double diffNA = y._NAsales - x._NAsales; double diffEU = y._EUsales - x._EUsales; return(diffNA * diffNA + diffEU * diffEU); }
/// <summary> /// Returns list of points in selected region around the specified point /// </summary> private static List <ClusterGame> GetNeighbours(List <ClusterGame> points, ClusterGame p, double region) { List <ClusterGame> reg = new List <ClusterGame>(); for (int i = 0; i < points.Count; i++) { double dist = Dist(p, points[i]); if (dist <= region) { reg.Add(points[i]); } } return(reg); }
/// <summary> /// DBSCAN clustering function on the list of points /// </summary> private static List <List <ClusterGame> > StartClustering(List <ClusterGame> points, double region, int min_points) { region = square(region); int ClstId = 1; if (points == null) { return(null); } List <List <ClusterGame> > clusters = new List <List <ClusterGame> >(); for (int counter = 0; counter < points.Count; counter++) { ClusterGame p = points[counter]; if (p._cluster == ClusterGame._checked) { if (CheckCluster(points, p, ClstId, region, min_points)) { ClstId++; } } } // Assign point to clusters int max = points.OrderBy (p => p._cluster).Last()._cluster; if (max < 1) { return(clusters); } for (int i = 0; i < max; i++) { clusters.Add(new List <ClusterGame>()); } foreach (ClusterGame p in points) { if (p._cluster > 0) { clusters[p._cluster - 1].Add(p); } } return(clusters); }
/// <summary> /// Check if the cluster can be expanded /// </summary> private static bool CheckCluster(List <ClusterGame> points, ClusterGame p, int clusterId, double region, int min_points) { List <ClusterGame> neighboursList = GetNeighbours(points, p, region); // mark point as NOISE if the count of neighbours is bellow treshold if (neighboursList.Count < min_points) { MarkNoise(p); return(false); } //Expand cluster if the count of neighbours is above treshold else { //Remove points from the list for (int i = 0; i < neighboursList.Count; i++) { neighboursList[i]._cluster = clusterId; } neighboursList.Remove(p); //Repeat for every neighbour point while (neighboursList.Count > 0) { ClusterGame current = neighboursList[0]; List <ClusterGame> result = GetNeighbours(points, current, region); if (result.Count >= min_points) { for (int i = 0; i < result.Count; i++) { ClusterGame res = result[i]; if (res._cluster == ClusterGame._checked || res._cluster == ClusterGame._isnoise) { if (res._cluster == ClusterGame._checked) { neighboursList.Add(res); } res._cluster = clusterId; } } } neighboursList.Remove(current); } return(true); } }
private static void MarkNoise(ClusterGame p) { p._cluster = ClusterGame._isnoise; }
/// <summary> /// Returns cluster with the biggest amount of point aka best candidate /// </summary> private static List <ClusterGame> BestCluster(List <ClusterGame> points, double maxDiameter) { double diametersqrd = maxDiameter * maxDiameter; List <List <ClusterGame> > c = new List <List <ClusterGame> >(); List <ClusterGame> cc = null; int[] candidateNumbers = new int[points.Count]; int totalPointsAllocated = 0; int currentCandidateNumber = 0; for (int i = 0; i < points.Count; i++) { if (totalPointsAllocated == points.Count) { break; } if (candidateNumbers[i] > 0) { continue; } currentCandidateNumber++; cc = new List <ClusterGame>(); cc.Add(points[i]); candidateNumbers[i] = currentCandidateNumber; totalPointsAllocated++; ClusterGame latestPoint = points[i]; double[] diametersSquared = new double[points.Count]; while (true) { if (totalPointsAllocated == points.Count) { break; } int closest = -1; double minDiameterSquared = Int32.MaxValue; for (int j = i + 1; j < points.Count; j++) { if (candidateNumbers[j] > 0) { continue; } double distSquared = Dist(latestPoint, points[j]); if (distSquared > diametersSquared[j]) { diametersSquared[j] = distSquared; } if (diametersSquared[j] < minDiameterSquared) { minDiameterSquared = diametersSquared[j]; closest = j; } } if ((double)minDiameterSquared <= diametersqrd) { cc.Add(points[closest]); candidateNumbers[closest] = currentCandidateNumber; totalPointsAllocated++; } else { break; } } c.Add(cc); } int maxPoints = -1; int bestCandidateNumber = 0; for (int i = 0; i < c.Count; i++) { if (c[i].Count > maxPoints) { maxPoints = c[i].Count; bestCandidateNumber = i + 1; } } for (int i = candidateNumbers.Length - 1; i >= 0; i--) { if (candidateNumbers[i] == bestCandidateNumber) { points.RemoveAt(i); } } return(c[bestCandidateNumber - 1]); }