/***************************************************/ /**** Public Methods ****/ /***************************************************/ public static List <List <T> > ClusterDBSCAN <T>(this List <T> items, Func <T, T, bool> metricFunction, int minCount = 1) { DBSCANObject <T>[] DBSCANItems = items.Select(x => Create.DBSCANObject <T>(x)).ToArray(); int c = 0; for (int i = 0; i < DBSCANItems.Length; i++) { DBSCANObject <T> p = DBSCANItems[i]; if (p.IsVisited) { continue; } p.IsVisited = true; DBSCANObject <T>[] neighbourItems = null; RegionQuery(DBSCANItems, p.ClusterItem, metricFunction, out neighbourItems); if (neighbourItems.Length < minCount) { p.ClusterId = -1; } else { c++; ExpandCluster(DBSCANItems, p, neighbourItems, metricFunction, c, minCount); } } List <List <T> > clusters = new List <List <T> >( DBSCANItems .Where(x => x.ClusterId > 0) .GroupBy(x => x.ClusterId) .Select(x => x.Select(y => y.ClusterItem).ToList()) ); return(clusters); }
/***************************************************/ /**** Private methods ****/ /***************************************************/ private static void ExpandCluster <T>(DBSCANObject <T>[] allItems, DBSCANObject <T> item, DBSCANObject <T>[] neighbourItems, Func <T, T, bool> metricFunction, int c, int minCount) { item.ClusterId = c; for (int i = 0; i < neighbourItems.Length; i++) { DBSCANObject <T> neighbourItem = neighbourItems[i]; if (!neighbourItem.IsVisited) { neighbourItem.IsVisited = true; DBSCANObject <T>[] neighbourItems2 = null; RegionQuery(allItems, neighbourItem.ClusterItem, metricFunction, out neighbourItems2); if (neighbourItems2.Length >= minCount) { neighbourItems = neighbourItems.Union(neighbourItems2).ToArray(); } } if (neighbourItem.ClusterId == 0) { neighbourItem.ClusterId = c; } } }