Score a clustering without any ground truth labels.
For each point i:
a(i) = mean distance from i to the other points in its own cluster
b(i) = min over other clusters C of the mean distance from i to the points in C
s(i) = (b(i) - a(i)) / max(a(i), b(i))
Return the mean of s(i) over all points.
The score runs from -1 to 1. Near 1 means points sit much closer to their
own cluster than to any other; near 0 means they sit on a boundary; negative
means they would be better off elsewhere.
Two cases need handling:
a(i)
is undefined. Define s(i) = 0 for singletons, which is the standard
convention.b(i) does not exist. Return 0.0.Note that a(i) excludes the point itself. Including its own zero distance
would shrink a towards zero and inflate every score.
Use Euclidean distance.
def silhouette_score(X, labels):
Input
X = np.array([[0.0], [0.1], [10.0], [10.1]])
labels = np.array([0, 0, 1, 1])
silhouette_score(X, labels)
Output
0.9899997499937498
Reasoning
For each point, a is 0.1, the distance to its one cluster mate. b is about 10, the mean distance to the other cluster. So every s(i) is close to 1 - 0.1 / 10 = 0.99.
a(i) leaves out the point itself.0.0.0.Check runs the visible cases against a fresh kernel. Submit runs the hidden ones too.
⇧↵run cell