Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions benchmarks/Clusterers/SLINKBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

namespace Rubix\ML\Benchmarks\Clusterers;

use Rubix\ML\Clusterers\SLINK;
use Rubix\ML\Datasets\Generators\Blob;
use Rubix\ML\Datasets\Generators\Agglomerate;
use Rubix\ML\Datasets\Labeled;

/**
* @Groups({"Clusterers"})
* @BeforeMethods({"setUp"})
*/
class SLINKBench
{
/**
* The number of samples in the training set.
*/
protected const int TRAINING_SIZE = 10000;

/**
* The number of samples in the testing set.
*/
protected const int TESTING_SIZE = 10000;

protected Labeled $training;

protected Labeled $testing;

protected SLINK $estimator;

public function setUp() : void
{
$generator = new Agglomerate([
'Iris-setosa' => new Blob(
center: [5.0, 3.42, 1.46, 0.24],
stdDev: [0.35, 0.38, 0.17, 0.1]
),
'Iris-versicolor' => new Blob(
center: [5.94, 2.77, 4.26, 1.33],
stdDev: [0.51, 0.31, 0.47, 0.2]
),
'Iris-virginica' => new Blob(
center: [6.59, 2.97, 5.55, 2.03],
stdDev: [0.63, 0.32, 0.55, 0.27]
),
]);

$this->training = $generator->generate(self::TRAINING_SIZE);
$this->testing = $generator->generate(self::TESTING_SIZE);
$this->estimator = new SLINK(3);
}

/**
* @Subject
* @Iterations(5)
* @OutputTimeUnit("seconds", precision=3)
*/
public function trainPredict() : void
{
$this->estimator->train($this->training);
$this->estimator->predict($this->testing);
}
}
1 change: 1 addition & 0 deletions docs/choosing-an-estimator.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Clusterers are unsupervised learners that predict an integer-valued cluster numb
| [K Medoids](clusterers/k-medoids.md) | Low | ● | | ● | ● | Depends on distance kernel |
| [Mean Shift](clusterers/mean-shift.md) | Medium | ● | | ● | ● | Continuous |
| [OPTICS](clusterers/optics.md) | High | ● | | ● | ● | Depends on distance kernel |
| [SLINK](clusterers/slink.md) | Low | ● | | ● | ● | Depends on distance kernel |
| [Ward](clusterers/ward.md) | Low | ● | | ● | ● | Continuous |

## Anomaly Detectors
Expand Down
59 changes: 59 additions & 0 deletions docs/clusterers/slink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<span style="float:right;"><a href="https://github.com/RubixML/ML/blob/master/src/Clusterers/SLINK.php">[source]</a></span>

# SLINK

An *agglomerative* (bottom-up) hierarchical clustering algorithm that groups samples by the *single-link* criterion, named after the optimally efficient algorithm of *R. Sibson*. Unlike the iterative re-estimation schemes used by [K Means](k-means.md) or [K Medoids](k-medoids.md), SLINK begins with each sample as its own singleton cluster and then greedily merges the pair of clusters whose closest pair of members is nearest, repeating until the target number of clusters *k* remains. Merging halts early if the distance of the next closest pair of clusters exceeds `maxDistance`, which — defaulted to `INF` — permits the full *n - k* merges.

The distance kernel and the data types the estimator is compatible with are those of the tree. By default, SLINK uses a [Ball Tree](../graph/trees/ball-tree.md) with a Euclidean kernel, which accepts any *subadditive* distance kernel. A [KD Tree](../graph/trees/k-d-tree.md) can be substituted when a *monotonic* kernel is required. The algorithm is fully deterministic and requires no seeding, initialization, or epoch tuning.

**Interfaces:** [Estimator](../estimator.md), [Learner](../learner.md), [Persistable](../persistable.md), [Verbose](../verbose.md)

**Data Type Compatibility:** Depends on distance kernel of the tree

## Parameters

| # | Name | Default | Type | Description |
| --- | --- | --- | --- | --- |
| 1 | k | | int | The number of target clusters. |
| 2 | maxDistance | INF | float | The maximum single-link distance any single merge may incur. Training stops early once the next closest pair of clusters exceeds this threshold. Defaults to `INF` (no limit). |
| 3 | tree | BallTree | Spatial | The spatial tree used to store the training samples and their labels and to search for nearest neighbors. |

## Example

```php
use Rubix\ML\Clusterers\SLINK;
use Rubix\ML\Graph\Trees\BallTree;
use Rubix\ML\Kernels\Distance\Manhattan;

$estimator = new SLINK(3, INF, new BallTree(kernel: new Manhattan()));
```

## Additional Methods

Return the spatial tree that stores the training samples and their cluster labels.

```php
public tree() : Spatial
```

Return the number of training samples that each cluster is responsible for.

```php
public sizes() : int[]|null
```

Return the single-link merge height — the distance between the closest pair of members of the two clusters — for each of the merges from the last training session.

```php
public losses() : float[]|null
```

Return the progress table combining the merge height recorded at each agglomeration round of the last training session into a single ordered sequence.

```php
public progress() : iterable
```

## References

[^1]: R. Sibson. (1973). SLINK: An Optimally Efficient Algorithm for the Single-Link Cluster Method. The Computer Journal, 16(1), 30-34.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ nav:
- K Medoids: clusterers/k-medoids.md
- Mean Shift: clusterers/mean-shift.md
- OPTICS: clusterers/optics.md
- SLINK: clusterers/slink.md
- Ward: clusterers/ward.md
- Anomaly Detectors:
- Gaussian MLE: anomaly-detectors/gaussian-mle.md
Expand Down
Loading
Loading