Documentation
¶
Overview ¶
Package cohort partitions a fleet into groups of clusters that look like each other. User-supplied tags win when present. Without tags, agglomerative clustering on a feature vector groups similar clusters so that drift detection can run within cohort instead of across the entire fleet.
Index ¶
Constants ¶
const DefaultTagKey = "cohort"
DefaultTagKey is the cluster-tag key that carries a cohort label.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ClusterProfile ¶
type ClusterProfile struct {
// Name is the cluster name.
Name string
// Features is the normalized feature vector. All profiles share the
// same feature order.
Features []float64
// Tag is the user-supplied cohort label, "" when unset.
Tag string
}
ClusterProfile is the per-cluster input to Assign. Features must be aligned across profiles, in the same order, and already normalized to roughly [0,1]. Tag is the user-supplied cohort label or "" if none was set.
func Profiles ¶
func Profiles(clusters []string, sections SectionLookup, tags map[string]string) []ClusterProfile
Profiles builds normalized feature vectors for every cluster in the fleet. Each feature is min-max normalized across the fleet to [0,1] so dimensions with large absolute ranges do not dominate distance calculations. Missing values are imputed with the per-feature fleet median before normalization. tags maps cluster name to its user-supplied cohort label (empty string when none).
type Cohort ¶
type Cohort struct {
// Name is the cohort label. For tagged cohorts this is the tag value.
// For auto-detected cohorts this is "auto-N" with a stable index.
Name string `json:"name"`
// Source identifies how this cohort was produced.
Source Source `json:"source"`
// Clusters lists the member cluster names, sorted for stable output.
Clusters []string `json:"clusters"`
}
Cohort is a group of clusters that look similar enough to share a baseline.
func Assign ¶
func Assign(profiles []ClusterProfile, opts Options) []Cohort
Assign partitions clusters into cohorts. Profiles carrying a non-empty Tag land in tagged cohorts named after the tag. Untagged profiles get auto-assigned via average-linkage agglomerative clustering on their feature vectors, with K chosen from the largest gap in the merge sequence. When the fleet is too small to subdivide, every cluster lands in a single "fleet" cohort.
type Map ¶ added in v0.10.0
type Map struct {
// Points holds one entry per cluster, in profile order.
Points []MapPoint `json:"points"`
// LeafOrder lists every cluster with each cohort as one contiguous run.
// Cohorts appear in the order their first member appears in the
// dendrogram's leaf order, and members keep that leaf order within a run.
LeafOrder []string `json:"leaf_order"`
// Stress is Kruskal's stress-1 of the 2D layout against the feature
// distances: 0 is a perfect fit, and above about 0.2 the picture is a
// rough guide.
Stress float64 `json:"stress"`
}
Map is a two-dimensional picture of a fleet's cohort feature vectors: where each cluster sits, which clusters it is closest to, and an order that keeps every cohort contiguous for a seriated matrix.
func BuildMap ¶ added in v0.10.0
func BuildMap(profiles []ClusterProfile, cohorts []Cohort, peers int) Map
BuildMap lays profiles out in two dimensions with classical multidimensional scaling of their pairwise feature distances, lists up to peers nearest neighbors per cluster, and orders clusters for a seriated view. cohorts assigns each profile its cohort name; a profile in no cohort gets an empty one.
type MapPoint ¶ added in v0.10.0
type MapPoint struct {
// Cluster is the cluster name.
Cluster string `json:"cluster"`
// Cohort is the name of the cohort the cluster belongs to.
Cohort string `json:"cohort"`
// X is the first classical MDS coordinate.
X float64 `json:"x"`
// Y is the second classical MDS coordinate.
Y float64 `json:"y"`
// Peers lists the nearest other clusters by feature distance, closest
// first.
Peers []Peer `json:"peers,omitempty"`
}
MapPoint is one cluster on the cohort map.
type Options ¶
type Options struct {
// MinClusters is the fleet size below which auto-cohorting is skipped.
// Zero means use the package default.
MinClusters int
// MinCohortSize is the smallest cohort the algorithm will keep.
// Cohorts below this size are folded into their nearest neighbor.
// Zero means use the package default.
MinCohortSize int
// MaxCohorts caps the number of auto-detected cohorts.
// Zero means use the package default.
MaxCohorts int
}
Options controls cohort assignment.
type Peer ¶ added in v0.10.0
type Peer struct {
// Cluster is the peer's name.
Cluster string `json:"cluster"`
// Distance is the Euclidean distance between the two feature vectors.
Distance float64 `json:"distance"`
}
Peer is a nearby cluster and its feature distance.
type SectionLookup ¶
type SectionLookup interface {
// PerCluster returns the raw per-cluster data for a scanner. The map key
// is the cluster name. Returns nil when the scanner is absent.
PerCluster(scanner string) map[string]any
}
SectionLookup is the minimal interface Profiles needs to walk a Report without depending on the report package. Callers wrap their Report.Sections in something that satisfies this.
type Source ¶
type Source string
Source indicates how a cohort was determined.
const ( // SourceTagged means the cohort came from a user-supplied cluster tag. SourceTagged Source = "tagged" // SourceAuto means the cohort was derived by clustering scanner data. SourceAuto Source = "auto" // SourceFleet means the fleet was too small or too uniform to subdivide. SourceFleet Source = "fleet" )