Open-source agentic AI for transaction monitoring. Just ask Jooby.What's Jube? →

Multivariate and clustering tool catalogue

The product’s semantic tool layer for grouping rows, comparing cases and reducing dimensionality: Jube.Service.Agent.AdvancedAnalyticsTools.MultivariateAndClustering carries 52 tools across six classes, covering clustering algorithms, the measures used to evaluate and use a clustering, discriminant analysis and multivariate outlier detection, distance and kernel functions (including string and set similarity), nearest neighbour search and association rule mining, and principal/independent component analysis. AskJooby’s validator agent (Jadek) only confirms a claim against prose indexed from docs/, and none of these 52 tool names appears anywhere else in the documentation tree, so this page is the only place a claim about what one of them does or returns can be confirmed.

Clustering algorithms

These eleven tools, all on ClusteringTools, partition rows into groups by different rules. Every one of them accepts rows as double[][] (or, for k-modes, int[][] category codes) and, unless noted, standardises each column to zero mean and unit variance before clustering when standardise is true (the default), so that a column measured in large units does not dominate the distance calculation; centroids and cluster profiles are always reported back in the original units regardless. A shared result shape underlies most of them: a cluster label per row (0 to k minus 1), the centroids in original units, a profile per cluster (size, share of rows, per-column mean and standard deviation, within-cluster sum of squares, and mean/maximum distance of members to the centroid), the total inertia (summed squared distance to centroids, which always falls as k rises), and the mean silhouette score (between -1 and 1, NaN above 5,000 rows or with a single cluster, because the silhouette needs every pairwise distance). A cluster left empty by a run has size 0 and NaN centroid values.

“RunKMeansClustering” runs ordinary k-means: starting centres are chosen either by k-means++ (which spreads them apart) or Uniform (random rows), each row is assigned to its nearest centre under the chosen distance (Euclidean by default; Manhattan, Chebyshev and Cosine are common alternatives), and centres are re-estimated as cluster means until assignments stop changing or maximumIterations (default 100, capped at 1,000) is reached. It is bounded to 100,000 rows and 200 clusters. Converged is false when the iteration cap was hit before assignments stabilised. Because the result depends on the starting points, the seed parameter (default 1) should be varied and compared across runs before a solution is trusted.

“RunMiniBatchKMeansClustering” is a faster k-means variant for large row counts: instead of updating centres from every row each iteration it updates from a random batchSize (default 100, capped at the row count) sample per iteration. Results are close to, but not identical with, ordinary k-means, and depend on both the seed and the batch size. Bounds match plain k-means (100,000 rows, 200 clusters, 1,000 iterations).

“RunBinarySplitClustering” builds k clusters by repeatedly splitting the current set of clusters in two — the splitting stage of the LBG vector quantisation algorithm. Given the same seed it is deterministic, and because it grows by splitting it produces a hierarchy-like nested partition as k increases. Bounds and return shape match plain k-means.

“RunBalancedKMeansClustering” constrains cluster assignment so that no cluster absorbs a disproportionate share of the rows, trading some tightness (inertia is usually higher than plain k-means) for roughly equal cluster sizes. It is useful for splitting a portfolio into evenly sized review workloads. Because the constrained assignment step is quadratic in the row count it is bounded to 5,000 rows rather than 100,000, keeping the 200-cluster and 1,000-iteration caps.

“RunKMedoidsClustering” clusters around medoids — actual rows of the data chosen as cluster centres — rather than computed means, so each cluster has a real, explainable representative case, and the method tolerates outliers and non-Euclidean distances (the default metric is Manhattan rather than Euclidean) better than k-means. Its result differs from the shared shape: alongside the label per row it returns the row number and values of each medoid, a profile per cluster, the total distance of rows to their medoids under the chosen metric (lower is tighter), and the silhouette under that same metric (NaN for a single cluster). seeding can be PamBuild (the default, a greedy deterministic build), KMeansPlusPlus or Uniform; only the latter two consume the random seed. Because the assignment cost grows with the square of the row count, it is capped at 5,000 rows.

“RunKModesClustering” clusters rows of integer category codes — merchant category, channel, country and other attributes that should be encoded to integer codes before calling it — using k-modes: each cluster is represented by its mode (the most frequent category per column) and rows are assigned by Hamming distance (the count of mismatched columns) to the nearest mode. It returns the label per row, each cluster’s mode, cluster sizes, the total mismatch count across all rows (lower is tighter) and whether the run converged. Bounded to 100,000 rows, 200 clusters, 500 columns and 1,000 iterations.

“RunMeanShiftClustering” finds clusters as the peaks (modes) of the data’s density rather than choosing a cluster count up front: every row climbs uphill through a smoothed density estimate until it settles near a peak, and rows that reach the same peak form a cluster, so the number of clusters is discovered, not chosen. The only setting that really matters is bandwidth (the smoothing radius, default 1): small values yield many small clusters, large values merge everything; with standardise true the bandwidth is in standard deviations, making 0.5–2 a sensible search range. The smoothing kernel can be Gaussian (default), Uniform (a flat window) or Epanechnikov (a parabolic window). It returns the label per row, the mode found for each cluster, cluster sizes and a profile per cluster. Because every row is compared with every other row, it is bounded to 5,000 rows and 1,000 iterations.

“RunGaussianMixtureClustering” fits a Gaussian mixture by expectation maximisation, modelling the data as a weighted blend of components bell-shaped groups, each with its own mean and covariance. Unlike k-means this gives soft clusters (a probability of membership per component rather than a hard boundary) and can represent elongated or differently sized groups. It returns, per row, the most likely component and (optionally, via returnResponsibilities, default true) the full probability vector across components, which sums to 1; per component the weight (share of the data), mean and covariance matrix; and model-selection statistics — the log-likelihood (higher fits better), the parameter count, AIC and BIC (lower is better for both; BIC’s stronger complexity penalty makes it the usual choice for picking a component count). covariance can be Full (a complete covariance matrix per component) or Diagonal (variances only, far cheaper with many columns). regularization (default 1e-6) is added to the covariance diagonal to stop a component from collapsing onto a tiny or exactly repeated cluster. Bounded to 50,000 rows, 100 columns, 50 components and 1,000 iterations, and needs at least twice as many rows as components.

“SelectGaussianMixtureComponentsByBic” answers the model-selection question that RunGaussianMixtureClustering leaves open: it fits mixtures for every component count from minComponents to maxComponents (at most 15 values tried) and tabulates the log-likelihood, parameter count, AIC and BIC, and convergence flag for each, then reports BestComponentsByBic and BestComponentsByAic. BIC’s stronger penalty on extra components usually gives the more conservative answer. It is a natural tool to run before RunGaussianMixtureClustering to choose components, or to estimate how many distinct populations (customer segments, transaction types) likely exist in a data set.

“DetectAnomaliesWithGaussianMixture” uses a Gaussian mixture as an anomaly detector: it fits the mixture to referenceData only, then scores newData (or, if omitted, the reference rows themselves) by log probability density under that mixture — lower density means more unusual. The flagging threshold is the log density below which the lowest contamination share (default 0.01, i.e. 1 percent) of the reference rows themselves fall, so the contamination parameter calibrates the cutoff against the reference population’s own tail rather than an arbitrary constant. Because a mixture can represent several legitimate sub-populations at once, it can flag a row that fits none of several known-good groups — something a single-centre Mahalanobis distance cannot express. Bounded to 50,000 reference rows, 100 columns and 50 components.

“SelectKMeansPlusPlusSeeds” exposes the k-means++ seeding rule as a standalone tool: it draws seeds rows, the first uniformly at random and each subsequent one with probability proportional to its squared distance from the nearest already-chosen row, so the chosen rows are spread apart rather than clustered together. It returns the row numbers and values of the chosen rows. Beyond initialising other clustering methods, this is useful on its own for picking a diverse set of representative cases for manual review, since the same seed always reproduces the same selection. Bounded to 100,000 rows and 200 seeds.

Evaluating and using a clustering

These nine tools, all on ClusterEvaluationTools, take an existing labelling — from any of the clustering tools above, or from elsewhere — as double[][] data plus int[] labels (any integers; rows sharing a label form a cluster) and answer questions about its quality, its meaning, or how to apply it to new data. labels is validated and remapped to a contiguous 0-based range internally, so arbitrary label values are accepted.

“ComputeSilhouetteScores” computes, for every row, the standard silhouette: a is its mean distance to the other rows of its own cluster, b is its mean distance to the rows of the nearest other cluster, and the score is (b − a) / max(a, b), bounded between -1 and 1. A score near 1 means the row sits firmly inside its cluster, near 0 means it sits on a border between two clusters, and negative means it likely belongs to a different cluster than the one it was assigned to; a row that is alone in its own cluster scores 0 by convention. It returns every row’s score, each cluster’s mean score, and the overall mean — the single number usually quoted as cluster quality, where above roughly 0.5 indicates clear structure and below roughly 0.25 indicates weak structure. Because every pair of rows is compared, it needs at least 2 clusters and is capped at 5,000 rows.

“ComputeDaviesBouldinIndex” computes the Davies-Bouldin index: for each cluster it finds the most similar other cluster (similarity being the sum of the two clusters’ mean distances to their own centres, divided by the distance between the two centres) and averages those worst-case ratios across clusters. Lower is better, 0 is the unreachable ideal of infinitely tight and far-apart clusters, and values above roughly 1 indicate real overlap. It always uses Euclidean distance to the cluster means regardless of what distance produced the labelling, needs at least 2 clusters, and is capped at 100,000 rows. It is only meaningful for comparing different clusterings of the same data, never across data sets.

“ComputeCalinskiHarabaszIndex” computes the Calinski-Harabasz index (the variance ratio criterion): the between-cluster sum of squares divided by (k − 1), over the within-cluster sum of squares divided by (n − k). Higher is better, growing as clusters become more compact and more separated. It is infinite in the degenerate case where every row sits exactly on its centroid, and NaN when there is only one cluster or as many clusters as rows. Like Davies-Bouldin, it is intended for comparing different values of k on the same data set, not across data sets, and needs at least 2 clusters and at most 100,000 rows.

“EvaluateClusteringQuality” bundles the standard internal quality measures into one call for a clustering produced by any method, including one made outside these tools: inertia (within-cluster sum of squared distances to the means, lower is tighter), the between-cluster sum of squares, the mean silhouette (NaN above 5,000 rows), Davies-Bouldin (lower is better) and Calinski-Harabasz (higher is better). It is the tool to reach for to compare candidate clusterings of the same data without calling each measure separately. Needs at least 2 clusters and at most 100,000 rows; the distance parameter only affects the silhouette, since the other three measures are always Euclidean.

“ComputeKMeansElbowTable” helps choose a cluster count by running k-means for every k from minClusters to maxClusters (at most 30 values, using the same seed throughout for comparability) and tabulating, per k, the inertia (which always falls as k rises), mean silhouette, Davies-Bouldin and Calinski-Harabasz. ElbowClusters is the k at the sharpest bend in the inertia curve (the point furthest below the straight line joining the first and last points of the curve); BestClustersBySilhouette, ...ByDaviesBouldin and ...ByCalinskiHarabasz name the k each individual measure prefers. These measures routinely disagree with each other, so the guidance is to look for a k that several of them support rather than trusting any single one. Measures are computed on standardised data when standardise is true (the default). Bounded to 20,000 rows and 30 values of k; the silhouette column is NaN above 5,000 rows regardless of the overall row cap.

“ComputeKMeansGapStatistic” chooses a cluster count with Tibshirani’s gap statistic: for each k it compares the log of the real data’s k-means within-cluster dispersion against the average of that same quantity over referenceSets (default 10, capped at 20) synthetic data sets drawn uniformly at random inside the bounding box of the real data — so a large gap means the real data clusters far more tightly than random noise of the same shape would. The output table carries, per k, the observed log dispersion, the expected log dispersion under the reference, the gap, and its standard error; BestClusters applies Tibshirani’s one-standard-error rule (the smallest k whose gap is at least the next k’s gap minus that next k’s standard error), falling back to the largest k tried if no k qualifies. The reference sets are drawn using seed, so results repeat for a fixed seed. Because it fits many k-means models (one real plus referenceSets reference fits, per candidate k), it is tightly bounded: at most 5,000 rows, 15 values of k, and 20 reference sets.

“ProfileClusters” describes each cluster of an existing labelling in plain numbers so it can be interpreted without staring at raw centroids: size and share of rows, the centroid (mean per variable), the standard deviation per variable, the within-cluster sum of squares, the mean and maximum Euclidean distance of members to the centroid, and a ranked list of the variables that most distinguish the cluster. DistinguishingVariables lists, for the topVariables (default 3) variables with the largest effect, the standardised difference — (cluster mean − overall mean) / overall standard deviation — so +1.5 means the cluster averages 1.5 standard deviations above the rest of the population on that variable; a variable that is constant across all rows has effect exactly 0 rather than dividing by zero. It accepts labels from any clustering method, not just this tool group’s own output. A cluster containing only one row has NaN standard deviations, since a spread cannot be computed from a single point. Capped at 100,000 rows.

“AssignRowsToNearestCentroid” assigns new rows to the nearest of a supplied set of centroids — typically centroids returned by one of the clustering tools above — under a chosen distance metric (Euclidean by default; minkowskiOrder, default 3, configures the Minkowski metric). For each new row it returns the index of the nearest centroid (its position in the supplied centroid array, 0-based), the distance to that centroid, and the distances to every centroid, so that borderline rows can be spotted — a small gap between the two smallest distances flags an ambiguous assignment. It is the caller’s responsibility to keep the new rows on the same scale as the clustering: if the original clustering standardised its input, the new rows must be standardised the same way before being passed in. Bounded to 20,000 new rows and 200 centroids.

“CompareClusterAssignments” measures how much two independent clusterings of the same rows agree, independent of how each one happens to number its clusters, using pair counting over every pair of rows. RandIndex is the share of all row pairs on which the two clusterings agree (both together or both apart), between 0 and 1. AdjustedRandIndex corrects the Rand index for the agreement expected by chance alone, so 1 means the two partitions are identical, roughly 0 means no better than chance, and a negative value means worse than chance — this is the number to quote when stability or reproducibility is the question, for example comparing a clustering across random seeds, methods, or samples. PairJaccard is the share of pairs that are together in either clustering that are together in both. Two clusterings that are each a single cluster, or each all singletons, trivially score 1 on all three measures. Bounded between 2 and 1,000,000 rows, and labelsA/labelsB must be the same length.

Discriminant analysis, embeddings and Mahalanobis distance

These six tools live on DiscriminantAndEmbeddingTools and cover supervised class separation, nonlinear embedding for visualisation, and multivariate outlier detection by Mahalanobis distance.

“RunLinearDiscriminantAnalysis” finds the directions along which known classes are best separated — large spread between class means relative to spread within each class — and returns them together with every row’s coordinates in that space. There are at most (number of classes − 1) useful directions, and components (0 by default, meaning “use the maximum”) selects how many to keep. It reports class sizes, prevalence, and means; each direction’s eigenvalue (bigger means more separation, with between-class scatter weighted equally per class); each direction’s share of total separation and the running cumulative total; the direction vectors themselves; the class means projected into the new space; the projected coordinates of every row (when returnScores is true, the default); and a training accuracy figure from assigning every row to its nearest projected class mean. That accuracy is measured on the same rows used to fit the model, so it is optimistic and should be read as a measure of separability rather than of predictive performance. It needs at least 2 classes with at least 2 rows each, more rows in total than classes, and columns that are not perfectly collinear within any one class — a singular or perfectly separable within-class scatter is rejected with an explanation pointing at collinear or constant columns. Capped at 20,000 rows.

“RunKernelDiscriminantAnalysis” is the same idea carried out in the feature space of a kernel, so that classes separated by a curved rather than a straight boundary can still be pulled apart. It shares the kernel parameter set used throughout this tool group (kernel, kernelSigma, kernelGamma, kernelConstant, kernelDegree, kernelAlpha, kernelBeta — see the kernel reference under Distances and kernels, below) and returns eigenvalues, separation shares, the projected coordinates of every row, the classes’ projected means, and training accuracy as above; because class means and direction vectors live in the kernel’s implicit feature space rather than the original variables, those two fields come back empty. regularization (default 1e-4) is added to the within-class matrix to keep it invertible; a SingularMatrixException from the underlying library is caught and re-raised as an ArgumentException suggesting the caller raise regularization (for example to 0.01) or change the kernel parameters. Because the kernel matrix has (rows)² cells, it is capped at 1,000 rows rather than 20,000.

“ClassifyWithLinearDiscriminant” learns a linear discriminant model from labelled training rows and immediately assigns each row of newData to whichever class’s projected mean is nearest, without saving the fitted model anywhere. It returns the predicted label per new row and, per row, one score per class in the order of ClassLabels — the negative squared distance to that class’s mean in the discriminant space, so a larger (less negative) score means a better fit. It is offered as a quick, interpretable baseline classifier, or as a way to place new cases relative to known groups without the overhead of a full model lifecycle. Training needs at least 2 classes with at least 2 rows each, exactly as for RunLinearDiscriminantAnalysis.

“DetectMultivariateOutliersMahalanobis” flags rows that are unusual as a combination of variables, using the Mahalanobis distance: the number of standard deviations a row lies from the centre once the correlations between variables are accounted for, so a row can be flagged because two normally-correlated variables disagree with each other even if neither variable alone looks extreme. For each row it returns the distance, the squared distance, and a chi-square p-value with one degree of freedom per independent dimension found in the data (Rank); the cutoff is the distance whose chi-square tail probability equals significance (default 0.001, i.e. the 99.9th percentile), and rows beyond it are flagged. The centre and covariance are estimated from the same rows being tested — the classical rather than a robust estimator — so several genuinely extreme rows can inflate the covariance estimate and mask each other, and small samples make the chi-square approximation loose; these are real limitations to keep in mind when reading the result. When columns are perfectly collinear the implementation falls back to a pseudo-inverse of the covariance matrix, and Rank comes back lower than the column count to reflect that; a reference set with literally no variation in any column (rank 0) is rejected outright, since distances would be undefined. Needs at least 3 rows, capped at 20,000.

“ScoreMahalanobisDistanceAgainstReference” is the same Mahalanobis calculation but deliberately avoids the masking problem above: the centre and covariance are learned from referenceData only, and newData is scored against that fixed reference, so extreme rows in the test set can never contaminate the population they are being measured against. This is the version to reach for when testing new transactions or customers against clean history, rather than detecting outliers within a single pooled set. Both data sets must share the same column count; the reference set needs at least 3 rows, and both are capped at 20,000 rows.

“EmbedWithTsne” embeds high-dimensional rows into 2 or 3 dimensions with t-SNE so that cluster structure can be seen on a scatter plot: points that are near each other in the original space stay near each other in the embedding, but distances between far-apart groups and the apparent size of a cluster in the embedding carry no meaning and should never be read as distances or densities. perplexity (default 30) is roughly the number of neighbours each point considers and must stay below one third of (rows − 1); the tool automatically reduces it to fit small samples, and a request with fewer than 10 rows is rejected outright as too few for a meaningful embedding. theta (default 0.5) trades speed for accuracy in the Barnes-Hut approximation, where 0 is exact but slow and 0.5 is the usual practical choice. The optimisation always runs 1,000 iterations from a random start controlled by seed, so the same seed reproduces the same coordinates, but different seeds give different, equally valid layouts of the same structure — comparisons across runs should be about the shapes found, never the raw coordinates. Bounded to 2,000 rows and 500 columns.

Distances, kernels and string similarity

These thirteen tools live on DistanceAndKernelTools and expose the numeric distance/kernel machinery used throughout this tool group as first-class, directly callable primitives, plus a matching set of tools for comparing text and token sequences.

“ComputeVectorDistance” computes a single distance between two equal-length numeric vectors under one named metric: Euclidean, SquaredEuclidean, Manhattan, Chebyshev, Minkowski (order set by minkowskiOrder, default 3; order 1 is Manhattan and order 2 is Euclidean), Cosine (1 minus cosine similarity), Angular (an angle in radians), Canberra, BrayCurtis, Hellinger (intended for non-negative probability-like vectors), PearsonCorrelation (1 minus correlation), and the binary family Hamming, Jaccard, Dice, Matching, Kulczynski, RogersTanimoto, RusselRao, SokalMichener, SokalSneath and Yule, all of which treat any non-zero value as “true”. Zero always means identical vectors, and larger values always mean more different, except that for Cosine, Jaccard and Dice the corresponding similarity is one minus the returned distance. weights supplies one non-negative weight per dimension and is only consulted for the WeightedEuclidean and WeightedSquaredEuclidean metrics. Non-finite inputs or mismatched vector lengths are rejected with an explanatory message rather than propagating NaN.

“ComputeDistanceMatrixWithinSet” computes the full symmetric pairwise distance matrix for one data set under any of the metrics above: cell [i][j] is the distance from row i to row j, the diagonal is exactly zero, and the matrix is symmetric. It is the building block for inspecting similarity structure, feeding a clustering algorithm, or finding near-duplicate rows. Because the result has (rows)² cells, it is capped at 2,000 rows; the summary carries the smallest, largest, and mean off-diagonal distance.

“ComputeDistanceMatrixBetweenSets” is the rectangular equivalent for two different data sets: cell [i][j] compares row i of setA with row j of setB, so the matrix need not be square and has no meaningful diagonal. Each set is independently capped at 2,000 rows, and both sets must share the same column count. Use it to compare a batch of new cases against a fixed reference population without computing the within-set distances for either side.

“ComputeKernelValue” evaluates a single named kernel function between two vectors, returning one similarity number where larger means more alike (the inverse sense of a distance). The kernel family is shared across every kernel-consuming tool in this group: Linear, Polynomial and Sigmoid are dot-product kernels; Gaussian, Laplacian, Cauchy, Spherical, Circular, Wave and ThinPlateSpline are distance kernels controlled by kernelSigma; Hypersecant, SquaredSinc and SymmetricTriangle use kernelGamma; Power, Log, TStudent, BSpline and Bessel use kernelDegree; and ChiSquare, Hellinger and HistogramIntersection are intended for non-negative, histogram-shaped data. kernelConstant supplies the additive constant used by the dot-product kernels (defaulting to 0 for Linear, i.e. a plain dot product, and 1 for the others), kernelAlpha is the sigmoid slope / Pearson omega / HistogramIntersection exponent, and kernelBeta is the HistogramIntersection beta exponent. This tool is the place to sanity-check a kernel and its parameters on one pair of cases before committing to it inside kernel PCA or kernel discriminant analysis.

“ComputeKernelGramMatrix” computes the full kernel (Gram) matrix for one data set: cell [i][j] is the kernel similarity between row i and row j, so the matrix is symmetric and the diagonal holds each row’s self-similarity. With normalise true (default false) every cell is divided by the square root of the product of its two diagonal entries — a cosine-style normalisation that forces the diagonal to exactly 1 and makes magnitudes comparable across different kernel choices. Capped at 1,000 rows because the matrix has (rows)² cells.

“ComputeKernelCrossMatrix” is the rectangular cross-kernel equivalent: cell [i][j] compares row i of setA with row j of setB under the chosen kernel, each set capped at 1,000 rows and both needing the same column count. Since the matrix is not square, its Diagonal field in the result comes back empty rather than meaningless.

“CompareHistogramsBhattacharyya” measures how much two discrete distributions overlap, each given as an array of non-negative counts or proportions over the same categories or bins in the same order; both arrays are first rescaled to sum to 1 internally. It returns the Bhattacharyya coefficient (1 for identical distributions, 0 for no overlap whatsoever), the Bhattacharyya distance (minus the natural log of the coefficient — 0 for identical, infinite for no overlap), and the Hellinger distance (the square root of one minus the coefficient, bounded between 0 and 1). The intended use is comparing a current distribution against a baseline, for example transaction amount bands this month against last month. At least one entry in each histogram must be above zero; a mismatched bin count or a negative entry is rejected.

“CompareSamplesBhattacharyyaGaussian” is the continuous, multivariate analogue: it fits a Gaussian (mean and covariance) to each of two samples and returns the Bhattacharyya distance between the two fitted Gaussians, a single number that grows with both the separation of the two means and the difference between the two covariances — 0 means the fitted Gaussians coincide exactly, and for two Gaussians sharing an identity covariance it reduces to one eighth of the squared distance between the means. It is intended to quantify drift between a baseline population and a current one across several variables at once. Each sample needs at least 3 rows, and the two must share the same column count.

“ComputeStringDistance” computes the edit distance between two strings under one of three named algorithms: Levenshtein (the minimum count of single-character insertions, deletions and substitutions turning one string into the other — the default), NormalisedLevenshtein (the same distance divided by the longer string’s length, so 0 is identical and 1 is completely different regardless of length), or Hamming (the count of differing positions, requiring both strings be the same length). ignoreCase (default true) lowercases both strings before comparing. Strings over 2,000 characters are rejected. The returned Similarity is always 1 minus the normalised distance, bounded between 0 and 1, which is the natural field to threshold when fuzzy-matching names, references or account descriptions that may carry typing errors.

“FindClosestStringMatches” ranks a list of candidates against one query string and returns the top (default 5) closest, nearest first, under the same three edit-distance algorithms as ComputeStringDistance. Similarity is 1 minus the distance divided by the longer of the two lengths being compared, so an exact match scores 1; Hamming candidates whose length differs from the query are silently skipped rather than erroring, since Hamming distance is undefined between strings of different lengths. Ties in distance preserve the original candidate order. Bounded to 5,000 candidates of at most 2,000 characters each, and top is capped at 1,000.

“ComputeStringDistanceMatrix” computes the full pairwise edit-distance matrix across one list of strings, symmetric with a zero diagonal, under any of the three algorithms above; for Hamming, every string in the list must share the same length. It is intended for finding near-duplicate names or references in bulk, or as a preparatory step before clustering text values. Capped at 500 strings of at most 2,000 characters each.

“ComputeTokenSequenceEditDistance” computes the edit distance between two ordered sequences of tokens — the sequence of actions in two user sessions, or the sequence of merchant categories in two customers’ histories — as the minimum number of single-token insertions, deletions and substitutions turning one sequence into the other, with order mattering throughout (unlike ComputeTokenSetSimilarity, below). It returns the raw distance and a similarity between 0 and 1 (1 minus the distance divided by the longer sequence’s length; two empty sequences score a similarity of 1 by convention). Each sequence is capped at 2,000 tokens, and ignoreCase (default true) applies to token text.

“ComputeTokenSetSimilarity” compares two lists of tokens — words, merchant categories, device identifiers, or any other strings — as unordered sets, collapsing duplicates and ignoring order entirely. It returns the size of each input set after deduplication, the intersection and union sizes, the Jaccard similarity (intersection over union), the Dice similarity (twice the intersection over the sum of the two set sizes), and the overlap coefficient (intersection over the smaller set size). All three similarity measures lie between 0 and 1, are 1 for identical sets, and are defined as 1 for two empty sets by convention (rather than the 0/0 that would otherwise result). Each token list is capped at 100,000 entries; ignoreCase (default true) folds case before comparing.

Nearest neighbours and association rules

These five tools live on NeighbourAndRuleTools. The first four share search machinery across three index choices — KdTree (the default, efficient for low-dimensional data), VpTree (works in any dimension, including non-Euclidean metrics) and BruteForce (a plain scan, giving identical results to the indexed searches and useful mainly as a cross-check) — and a metric choice of Euclidean (default), Manhattan, Chebyshev or Minkowski (order set by minkowskiOrder, default 3). Every one of them supports a “self-query” mode, triggered by leaving queryData null, in which every reference row queries against the rest of the reference set and is never returned as its own nearest neighbour.

“FindKNearestNeighbours” finds, for each query row, the neighbours (default 5) closest reference rows and their distances, nearest first. It is intended for finding look-alike customers, similar past cases, or near-duplicates. Scaling is the caller’s responsibility: columns on very different units should be standardised before calling, since all four metrics treat every dimension equally. Rows tied at exactly the same distance may be returned in either order, and which tied row is kept right at the cutoff is unspecified behaviour rather than a documented guarantee. Bounded to 100,000 reference rows, 5,000 query rows (5,000 self-queries when queryData is omitted), and 1,000 neighbours per query.

“FindNeighboursWithinRadius” is the radius-search sibling: for each query row it finds every reference row within radius (strictly, in the chosen metric’s own units) rather than a fixed count, using a KD-tree internally regardless of the index parameter’s value for the paired nearest-neighbour tool. It is suited to counting or listing cases inside a fixed similarity threshold, for example accounts within a small distance of a known suspicious profile. maxPerQuery (default 100) caps the list returned per query, keeping the nearest if the radius match count exceeds it. Bounded the same as FindKNearestNeighbours.

“ClassifyByNearestNeighbours” classifies each row of newData by a majority vote among its neighbours (default 5) nearest labelled training rows, with nothing about the model persisted anywhere. It returns the predicted label per new row (the plurality class among the neighbours, with ties broken in favour of the closer neighbours); per row, the share of the k neighbours voting for each class in the order of ClassLabels (a value of 0.6 means 6 of 10 neighbours belong to that class); and per row a distance-weighted share, where each neighbour contributes 1 / (1 + distance) so that nearer neighbours count for more than farther ones. It is offered as a transparent baseline classifier, and the per-class vote shares are also useful on their own as a measure of how mixed or unambiguous a case’s neighbourhood is. Training labels can be any integers; scaling is again the caller’s responsibility. Bounded to 100,000 training rows, 5,000 rows to classify, and 1,000 neighbours.

“DetectOutliersByNearestNeighbourDistance” is a density-based outlier check: for every row it computes the distance to its own k-th nearest other row (neighbours, default 5) and the mean distance to its k nearest, then flags rows whose k-th-neighbour distance exceeds the upper quartile of all such distances by more than iqrMultiplier (default 1.5) interquartile ranges — the familiar box-plot rule, applied to local neighbour distance rather than to the raw variable. Isolated rows naturally have large neighbour distances and get flagged; a tight cluster of several similar anomalies can mask itself if neighbours is not set larger than the group’s own size, so neighbours should be chosen above the size of the smallest anomalous group of interest. Scaling across columns is the caller’s responsibility. Needs at least 3 rows, and is capped at 5,000 rows and 1,000 neighbours.

“MineAssociationRules” finds items that frequently occur together across transactions — market-basket analysis — using the Apriori algorithm, and turns the frequent combinations into if-then rules. Each transaction is an array of item names (merchant categories, products, alert types, or any other categorical tag seen together for one customer or basket); repeated items within one transaction are collapsed. It returns the frequent itemsets — item groups present in at least minSupport (default 0.1, i.e. 10 percent) share of all transactions — and rules of the form “antecedent implies consequent” carrying support (the share of transactions containing both sides), confidence (the share of antecedent-containing transactions that also contain the consequent), lift (confidence divided by the consequent’s own support — above 1 means the two sides occur together more than chance would predict, exactly 1 means statistical independence), and leverage (support minus the product of the two sides’ individual supports). Rules are ordered by lift, then confidence. The bounds are deliberately tight to prevent combinatorial blow-up: at most 20,000 transactions, 12 distinct items within any one transaction, 200 distinct items overall, a minSupport floor of 0.001, and at most 5,000 itemsets and 1,000 rules returned (maxItemsets and maxRules, both independently settable within those ceilings).

Principal component and independent component analysis

These eight tools live on ProjectionTools and cover linear and kernel dimensionality reduction. basis is shared across the PCA-family tools: Correlation (the default) standardises every variable before extracting components, appropriate when variables are on different scales or units, while Covariance only centres the data and works directly in the original units, appropriate when the variables already share a common scale.

“RunPrincipalComponentAnalysis” finds the orthogonal directions that capture the most variance in the data and returns the eigenvalues (variance captured per component), the explained-variance ratios and their running cumulative total, the loadings (each component’s unit-length direction expressed in terms of the original variables), and — when returnScores is true (the default) — every row’s coordinates on the components. Scaled loadings (loading times the square root of the eigenvalue) are also returned; under the Correlation basis these equal each variable’s correlation with each component, and the accompanying communalities report the share of each variable’s own variance that the returned components explain. ComponentsForNPercent reports how many leading components are needed to reach given cumulative-variance thresholds, and KaiserComponentCount applies the Kaiser rule (components whose eigenvalue exceeds the mean eigenvalue — equivalently, exceeds 1 under the Correlation basis). Every loading vector’s sign is normalised so its largest-magnitude entry is positive, removing the otherwise arbitrary sign ambiguity of PCA. Needs at least 2 rows; constant columns are rejected outright under the Correlation basis, since a constant column cannot be standardised. With more columns than rows, only min(rows, columns) components exist. Capped at 20,000 rows and 500 columns.

“InterpretPrincipalComponents” turns the raw output of PCA into words: for the leading components (default 3) components it lists the topVariables (default 5) original variables with the largest absolute loadings on each, plus every variable’s communality. A component with large positive loadings on “amount” and “count”, for instance, reads as a volume component. Loading is the raw eigenvector weight (unit length per component), and SquaredLoadingShare is its square — the share of that component’s total direction a single variable accounts for. Variable names default to V0, V1, and so on if variableNames is omitted. This is meant to be run immediately after RunPrincipalComponentAnalysis to narrate what each retained component actually represents.

“ProjectOntoPrincipalComponents” learns principal components from referenceData and projects a separate newData set onto them, returning one score vector per new row. New rows are centred — and, under the Correlation basis, scaled — using the reference set’s own means and standard deviations, so the resulting scores are directly comparable with the reference rows’ own scores rather than being computed on a different footing. This is the tool for placing new cases into a component space that was learned from historical data. The reference set needs at least 2 rows, and both sets must share the same column count.

“WhitenDataWithPca” decorrelates and rescales data so the returned columns are mutually uncorrelated and each has variance exactly 1 — the classical PCA whitening transform, used as a preprocessing step for methods that assume roughly spherical input. Rows are projected onto the principal components and each resulting score column is divided by the square root of its own eigenvalue. Components whose eigenvalue falls below 1e-12 of the largest eigenvalue are silently dropped, since dividing by a near-zero eigenvalue would amplify noise rather than signal; as a result, for strongly collinear data the number of returned columns can be smaller than the number of input variables even when components requests more. ColumnStandardDeviations is returned specifically to let the caller confirm each retained column really does come back with variance 1. If every column turns out to have zero variance (nothing left to whiten), the call is rejected with an explanation rather than returning degenerate output.

“ComputePrincipalComponentDiagnostics” scores how unusual each row is relative to a PCA model learned from referenceData, using the two standard multivariate process-control statistics. HotellingT2 sums each retained component’s score squared and divided by its own eigenvalue — large when a row is extreme along the dominant patterns the model has retained. SquaredPredictionError is the squared distance, in centred (and, under Correlation, scaled) units, between a row and its reconstruction from only the retained components — large when a row breaks the correlation pattern the model assumes, regardless of where it sits along the retained directions. HotellingT2Cutoff is a chi-square critical value (a large-sample approximation) with one degree of freedom per retained component at the chosen significance (default 0.01); IsAbnormalT2 flags rows exceeding it. Test rows default to the reference rows themselves when testData is omitted, which is useful for diagnosing the reference population before scoring anything new against it.

“ReconstructFromPrincipalComponents” compresses rows onto the leading components (default 1) principal components learned from referenceData and maps them straight back to the original variables, returning both the reconstructed rows and, per row, a SquaredError — the squared distance between the original row and its reconstruction in the original units. Because rows that do not follow the dominant correlation pattern reconstruct poorly, SquaredError doubles directly as an interpretable anomaly score, distinct from but related to SquaredPredictionError above. RetainedVarianceRatio reports the share of the reference set’s total variance the kept components carry, useful for judging whether the chosen components count is actually enough. Test rows default to the reference rows when testData is omitted.

“RunKernelPrincipalComponentAnalysis” carries out PCA in the implicit feature space of a kernel rather than directly on the original variables, which lets it unfold curved or clustered structure — the canonical example being concentric rings, which a Gaussian kernel can separate but ordinary linear PCA cannot. It returns the eigenvalues of the centred kernel matrix, their explained-variance ratios (relative to however many components the analysis can extract, which is capped by the number of input variables), and the score of every row on the requested components (default 2). Because the kernel matrix has (rows)² cells, it is capped at 1,000 rows. kernelSigma for a Gaussian kernel should be chosen near the typical distance between neighbouring points in the data; as with ordinary PCA, the sign of each component’s scores is arbitrary (though repeatable for a fixed input) and carries no meaning on its own.

“RunIndependentComponentAnalysis” performs blind source separation: it looks for statistically independent, non-Gaussian source signals whose linear mixture would explain the observed columns — for example, separating overlapping underlying behaviours out of combined activity measurements. It returns the estimated source values (one column per extracted component, for every row), the mixing matrix (how the sources combine to produce the observed variables) and the demixing matrix (its inverse, mapping observations back to sources). algorithm can be Parallel (the default, estimating all components together) or Deflation (extracting them one at a time). As with any ICA method, the order, sign and scale of the recovered sources are arbitrary — a known, expected property rather than a defect — so results should be read for their shapes and relationships, never their raw magnitudes or which output column number corresponds to which real-world source. The optimisation starts from a random point controlled by seed (default 1), so a fixed seed reproduces a fixed result. It needs at least as many rows as columns and at least 2 columns, and is capped at 20,000 rows.

Coverage note

All 52 [AdvancedAnalyticsTool] names under Jube.Service/Agent/AdvancedAnalyticsTools/MultivariateAndClustering are documented above. None of these tools’ exact, quoted names appears anywhere else under docs/, including in docs/AnalyticalMethodology/OtherModelTypes/ (which documents KMeansClusterer, GaussianMixtureClusterer, PrincipalComponent, KNearestNeighboursClassifier and similar pages): those pages describe the standalone trained model feature of the same name and never cite the literal tool names captured here, which belong to a separate semantic tool layer that an agent calls directly.