7. Unsupervised Learning: PCA and Clustering

Lecture



Hello everyone! We invite you to study the seventh topic of our open machine learning course!

7. Unsupervised Learning: PCA and ClusteringThis session will be devoted to unsupervised learning methods, in particular principal component analysis (PCA) and clustering. You will learn why to reduce dimensionality in data, how to do it, and what ways there are to group similar observations in the data.

UPD: the course is now in English under the mlcourse.ai brand, with articles on Medium, and materials on Kaggle (Dataset) and on GitHub.

A video recording of the lecture based on this article, as part of the second run of the open course (September-November 2017).

List of articles in the series

  1. Primary data analysis with Pandas
  2. Visual data analysis with Python
  3. Classification, decision trees, and the nearest neighbors method
  4. Linear classification and regression models
  5. Compositions: bagging, random forest. Validation and learning curves
  6. Feature engineering and selection
  7. Unsupervised learning: PCA, clustering
  8. Learning on gigabytes with Vowpal Wabbit
  9. Time series analysis with Python
  10. Gradient boosting

Outline of this article

  1. Principal component analysis (PCA)
    • Intuition, theory, and features of application
    • Usage examples
  2. Clustering
    • K-means
    • Affinity Propagation
    • Spectral clustering
    • Agglomerative clustering
    • Clustering quality metrics
  3. Homework assignment
  4. Useful resources

0. Introduction

The main difference between unsupervised learning methods and the usual machine learning classification and regression tasks is that there is no labeling for the data in this case. This gives rise to several features at once — first, it becomes possible to use incomparably larger volumes of data, since they won't need to be labeled by hand for training, and second, there is uncertainty in measuring the quality of the methods, due to the absence of the same straightforward and intuitively clear metrics as in supervised learning tasks.

One of the most obvious tasks that comes to mind in the absence of explicit labeling is the task of dimensionality reduction of data. On one hand it can be viewed as an aid to data visualization, and the t-SNE method, which we covered in the second article of the course, is often used for this. On the other hand, this kind of dimensionality reduction can remove redundant, strongly correlated features from the observations and prepare the data for further processing in a supervised-learning setting, for example making the input data more "digestible" for decision trees.

1. Principal component analysis (PCA)

Intuition, theory, and features of application

Principal component analysis (PCA) is one of the most intuitively simple and frequently used methods for reducing the dimensionality of data and projecting it onto an orthogonal subspace of features.

7. Unsupervised Learning: PCA and ClusteringIn the most general terms, this can be thought of as the assumption that all our observations most likely look like a certain ellipsoid in a subspace of our original space, and that our new basis in this space coincides with the axes of that ellipsoid. This assumption lets us simultaneously get rid of strongly correlated features, since the basis vectors of the space we're projecting onto will be orthogonal.

In the general case, the dimensionality of this ellipsoid will equal the dimensionality of the original space, but our assumption that the data lies in a lower-dimensional subspace lets us discard the "extra" subspace in the new projection, namely the subspace along whose axes the ellipsoid is least stretched. We will do this "greedily", choosing in turn, as the next basis element of our new subspace, the axis of the ellipsoid from those remaining along which the variance is greatest.

"To deal with hyper-planes in a 14 dimensional space, visualize a 3D space and say 'fourteen' very loudly. Everyone does it." — Geoffrey Hinton

Let's consider how this is done mathematically:

To reduce the dimensionality of our data from 7. Unsupervised Learning: PCA and Clustering to 7. Unsupervised Learning: PCA and Clustering, we need to choose the top 7. Unsupervised Learning: PCA and Clustering axes of such an ellipsoid, sorted in decreasing order by variance along the axes.

Let's start by computing the variances and covariances of the original features. This is done simply using the covariance matrix. By the definition of covariance, for two features 7. Unsupervised Learning: PCA and Clustering and 7. Unsupervised Learning: PCA and Clustering their covariance will be

7. Unsupervised Learning: PCA and Clustering

where 7. Unsupervised Learning: PCA and Clustering is the expected value of the 7. Unsupervised Learning: PCA and Clustering-th feature.
Note here that covariance is symmetric, and the covariance of a vector with itself will equal its variance.

Thus the covariance matrix is a symmetric matrix, where the variances of the corresponding features lie on the diagonal, and off the diagonal are the covariances of the corresponding pairs of features. In matrix form, where 7. Unsupervised Learning: PCA and Clustering is the observation matrix, our covariance matrix will look like

7. Unsupervised Learning: PCA and Clustering

To refresh our memory — matrices, as linear operators, have this interesting property called eigenvalues and eigenvectors. These things are remarkable in that when our matrix acts on the corresponding linear space, the eigenvectors stay in place and are only multiplied by their corresponding eigenvalues. That is, they define a subspace which, under the action of this matrix as a linear operator, stays in place, or "maps into itself". Formally, an eigenvector 7. Unsupervised Learning: PCA and Clustering with eigenvalue 7. Unsupervised Learning: PCA and Clustering for a matrix 7. Unsupervised Learning: PCA and Clustering is simply defined as 7. Unsupervised Learning: PCA and Clustering.

The covariance matrix for our sample 7. Unsupervised Learning: PCA and Clustering can be represented as the product 7. Unsupervised Learning: PCA and Clustering. From the Rayleigh quotient it follows that the maximum variation of our dataset is achieved along the eigenvector of this matrix corresponding to the maximum eigenvalue. Thus, the principal components onto which we would like to project our data are simply the eigenvectors corresponding to the top 7. Unsupervised Learning: PCA and Clustering eigenvalues of this matrix.

The next steps are ridiculously simple — we just need to multiply our data matrix by these components and we will get a projection of our data onto the orthogonal basis of these components. Now, if we transpose our data matrix and the matrix of principal component vectors, we will recover the original sample in the space from which we made the projection onto the components. If the number of components was smaller than the dimensionality of the original space, we will lose some information in this transformation.

Usage examples

The iris flower dataset

Let's start by loading all the necessary modules and playing around with the familiar iris dataset, following the example from the scikit-learn package documentation.

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns; sns.set(style='white')
%matplotlib inline
from sklearn import decomposition
from sklearn import datasets
from mpl_toolkits.mplot3d import Axes3D

# Load our irises
iris = datasets.load_iris()
X = iris.data
y = iris.target

# Set up a nice 3D picture
fig = plt.figure(1, figsize=(6, 5))
plt.clf()
ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134)

plt.cla()

for name, label in [('Setosa', 0), ('Versicolour', 1), ('Virginica', 2)]:
    ax.text3D(X[y == label, 0].mean(),
              X[y == label, 1].mean() + 1.5,
              X[y == label, 2].mean(), name,
              horizontalalignment='center',
              bbox=dict(alpha=.5, edgecolor='w', facecolor='w'))
# Reorder the label colors so that they match correctly
y_clr = np.choose(y, [1, 2, 0]).astype(np.float)
ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=y_clr, cmap=plt.cm.spectral)

ax.w_xaxis.set_ticklabels([])
ax.w_yaxis.set_ticklabels([])
ax.w_zaxis.set_ticklabels([])

7. Unsupervised Learning: PCA and Clustering

Now let's see how much PCA improves the results for a model that, in this case, will handle classification poorly because it lacks the complexity to describe the data:

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, roc_auc_score

# Split off a validation set from our data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3,
                                                    stratify=y,
                                                    random_state=42)

# As an example, let's take a shallow decision tree
clf = DecisionTreeClassifier(max_depth=2, random_state=42)
clf.fit(X_train, y_train)
preds = clf.predict_proba(X_test)
print('Accuracy: {:.5f}'.format(accuracy_score(y_test,
                                                preds.argmax(axis=1))))

Out: Accuracy: 0.88889

Now let's try to do the same thing, but with data for which we have reduced the dimensionality to 2D:

# Run the PCA built into sklearn
pca = decomposition.PCA(n_components=2)
X_centered = X - X.mean(axis=0)
pca.fit(X_centered)
X_pca = pca.transform(X_centered)

# And plot the resulting points in our new space
plt.plot(X_pca[y == 0, 0], X_pca[y == 0, 1], 'bo', label='Setosa')
plt.plot(X_pca[y == 1, 0], X_pca[y == 1, 1], 'go', label='Versicolour')
plt.plot(X_pca[y == 2, 0], X_pca[y == 2, 1], 'ro', label='Virginica')
plt.legend(loc=0);

7. Unsupervised Learning: PCA and Clustering

# Repeat the same split into validation and training sets.
X_train, X_test, y_train, y_test = train_test_split(X_pca, y, test_size=.3,
                                                    stratify=y,
                                                    random_state=42)

clf = DecisionTreeClassifier(max_depth=2, random_state=42)
clf.fit(X_train, y_train)
preds = clf.predict_proba(X_test)
print('Accuracy: {:.5f}'.format(accuracy_score(y_test,
                                                preds.argmax(axis=1))))

Let's look at the increased classification accuracy:

Out: Accuracy: 0.91111

We can see that the quality increased only slightly, but for more complex, higher-dimensional data, where the data does not split trivially along a single feature, applying PCA can substantially improve the performance of decision trees and ensembles based on them.

Let's look at the 2 principal components in the last PCA representation of the data, and at the percentage of the original variance in the data that they "explain".

for i, component in enumerate(pca.components_):
    print("{} component: {}% of initial variance".format(i + 1,
          round(100 * pca.explained_variance_ratio_[i], 2)))
    print(" + ".join("%.3f x %s" % (value, name)
                     for value, name in zip(component,
                                            iris.feature_names)))

1 component: 92.46% of initial variance
0.362 x sepal length (cm) + -0.082 x sepal width (cm) + 0.857 x petal length (cm) + 0.359 x petal width (cm)
2 component: 5.3% of initial variance
0.657 x sepal length (cm) + 0.730 x sepal width (cm) + -0.176 x petal length (cm) + -0.075 x petal width (cm)

The handwritten digits dataset

Now let's take the handwritten digits dataset. We already worked with it in the 3rd article about decision trees and the nearest neighbors method.

digits = datasets.load_digits()
X = digits.data
y = digits.target

Let's recall what these digits look like — let's look at the first ten. Here, the images are represented by an 8 x 8 matrix (white-color intensity for each pixel). This matrix is then "unrolled" into a vector of length 64, giving the feature description of the object.

# f, axes = plt.subplots(5, 2, sharey=True, figsize=(16,6))
plt.figure(figsize=(16, 6))
for i in range(10):
    plt.subplot(2, 5, i + 1)
    plt.imshow(X[i,:].reshape([8,8]));

7. Unsupervised Learning: PCA and Clustering

It turns out that the dimensionality of the feature space here is 64. But let's reduce the dimensionality all the way down to 2, and we'll see that even by eye, the handwritten digits split fairly well into clusters.

pca = decomposition.PCA(n_components=2)
X_reduced = pca.fit_transform(X)

print('Projecting %d-dimensional data to 2D' % X.shape[1])

plt.figure(figsize=(12,10))
plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y,
            edgecolor='none', alpha=0.7, s=40,
            cmap=plt.cm.get_cmap('nipy_spectral', 10))
plt.colorbar()
plt.title('MNIST. PCA projection')

7. Unsupervised Learning: PCA and Clustering

Well, to be fair, with t-SNE the picture comes out even better, since PCA has a limitation — it only finds linear combinations of the original features. On the other hand, even on this relatively small dataset you can notice how much longer t-SNE takes to run.

%%time

from sklearn.manifold import TSNE
tsne = TSNE(random_state=17)

X_tsne = tsne.fit_transform(X)

plt.figure(figsize=(12,10))
plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y,
            edgecolor='none', alpha=0.7, s=40,
            cmap=plt.cm.get_cmap('nipy_spectral', 10))
plt.colorbar()
plt.title('MNIST. t-SNE projection')

7. Unsupervised Learning: PCA and Clustering

In practice, it's common to choose enough principal components to retain 90% of the variance of the original data. In this case, it's enough to select 21 principal components, i.e. to reduce the dimensionality from 64 features to 21.

pca = decomposition.PCA().fit(X)

plt.figure(figsize=(10,7))
plt.plot(np.cumsum(pca.explained_variance_ratio_), color='k', lw=2)
plt.xlabel('Number of components')
plt.ylabel('Total explained variance')
plt.xlim(0, 63)
plt.yticks(np.arange(0, 1.1, 0.1))
plt.axvline(21, c='b')
plt.axhline(0.9, c='r')
plt.show();

7. Unsupervised Learning: PCA and Clustering

2. Clustering

The intuitive formulation of the clustering problem is quite simple and amounts to us wanting to say: "Here I have a bunch of scattered points. I can see that they're falling into some clumps together. It would be great to be able to assign these points to clumps, and when a new point appears on the plane, to say which clump it falls into." From this formulation it's clear that there's a lot of room for imagination, and hence a corresponding variety of algorithms for solving this problem arises. The algorithms listed below by no means describe this variety in full, but are examples of the most popular methods for solving the clustering problem.

7. Unsupervised Learning: PCA and Clustering


Examples of clustering algorithms at work, from the scikit-learn package documentation

K-means

The K-means algorithm is probably the most popular and simplest clustering algorithm, and it can be represented very easily as simple pseudocode:

  1. Choose the number of clusters 7. Unsupervised Learning: PCA and Clustering that seems optimal to us for our data.
  2. Scatter 7. Unsupervised Learning: PCA and Clustering points (centroids) randomly across the space of our data.
  3. For each point in our dataset, compute which centroid it is closer to.
  4. Move each centroid to the center of the sample of points that we assigned to that centroid.
  5. Repeat the last two steps a fixed number of times, or until the centroids "converge" (this usually means that their displacement relative to their previous position does not exceed some predefined small value).

In the case of the ordinary Euclidean metric for points lying on a plane, this algorithm is very easy to work out analytically and to draw. Let's look at a corresponding example:

# Let's start by scattering three clusters of points on the plane
X = np.zeros((150, 2))

np.random.seed(seed=42)
X[:50, 0] = np.random.normal(loc=0.0, scale=.3, size=50)
X[:50, 1] = np.random.normal(loc=0.0, scale=.3, size=50)

X[50:100, 0] = np.random.normal(loc=2.0, scale=.5, size=50)
X[50:100, 1] = np.random.normal(loc=-1.0, scale=.2, size=50)

X[100:150, 0] = np.random.normal(loc=-1.0, scale=.2, size=50)
X[100:150, 1] = np.random.normal(loc=2.0, scale=.5, size=50)

plt.figure(figsize=(5, 5))
plt.plot(X[:, 0], X[:, 1], 'bo');


7. Unsupervised Learning: PCA and Clustering

# scipy has a nice function that computes distances
# between pairs of points from two arrays passed to it as input
from scipy.spatial.distance import cdist

# Fix the randomness and scatter three random centroids to start
np.random.seed(seed=42)
centroids = np.random.normal(loc=0.0, scale=1., size=6)
centroids = centroids.reshape((3, 2))

cent_history = []
cent_history.append(centroids)

for i in range(3):
    # Compute the distances from the observations to the centroids
    distances = cdist(X, centroids)
    # See which centroid each point is closest to
    labels = distances.argmin(axis=1)

    # Set each new centroid to the geometric center of its points
    centroids = centroids.copy()
    centroids[0, :] = np.mean(X[labels == 0, :], axis=0)
    centroids[1, :] = np.mean(X[labels == 1, :], axis=0)
    centroids[2, :] = np.mean(X[labels == 2, :], axis=0)

    cent_history.append(centroids)

# And now let's draw all this beauty
plt.figure(figsize=(8, 8))
for i in range(4):
    distances = cdist(X, cent_history[i])
    labels = distances.argmin(axis=1)

    plt.subplot(2, 2, i + 1)
    plt.plot(X[labels == 0, 0], X[labels == 0, 1], 'bo', label='cluster #1')
    plt.plot(X[labels == 1, 0], X[labels == 1, 1], 'co', label='cluster #2')
    plt.plot(X[labels == 2, 0], X[labels == 2, 1], 'mo', label='cluster #3')
    plt.plot(cent_history[i][:, 0], cent_history[i][:, 1], 'rX')
    plt.legend(loc=0)
    plt.title('Step {:}'.format(i + 1));


7. Unsupervised Learning: PCA and Clustering

It's also worth noting that although we considered the Euclidean distance, the algorithm will converge for any other metric as well, so for various clustering tasks, depending on the data, you can experiment not only with the number of steps or the convergence criterion, but also with the metric by which we compute the distances between points and cluster centroids.

Another feature of this algorithm is that it is sensitive to the initial position of the cluster centroids in space. In this situation, several consecutive runs of the algorithm followed by averaging of the resulting clusters comes to the rescue.

Choosing the number of clusters for kMeans

Unlike the classification or regression problem, in the case of clustering it is harder to choose a criterion that would make it easy to represent the clustering problem as an optimization problem.
For kMeans, the following criterion is common — the sum of squared distances from the points to the centroids of the clusters they belong to.

7. Unsupervised Learning: PCA and Clustering

here 7. Unsupervised Learning: PCA and Clustering is the set of clusters of cardinality 7. Unsupervised Learning: PCA and Clustering, and 7. Unsupervised Learning: PCA and Clustering is the centroid of cluster 7. Unsupervised Learning: PCA and Clustering.

It's clear that there's common sense in this: we want the points to be located close together near the centers of their clusters. But here's the catch: the minimum of such a functional is achieved when there are as many clusters as there are points (that is, each point is a cluster of one element).
To resolve this issue (choosing the number of clusters), the following heuristic is often used: choose the number of clusters starting from which the functional described, 7. Unsupervised Learning: PCA and Clustering, falls off "no longer so fast". Or, more formally:

7. Unsupervised Learning: PCA and Clustering

Let's look at an example.

from sklearn.cluster import KMeans

inertia = []
for k in range(1, 8):
    kmeans = KMeans(n_clusters=k, random_state=1).fit(X)
inertia.append(np.sqrt(kmeans.inertia_))

plt.plot(range(1, 8), inertia, marker='s');
plt.xlabel('$k$')
plt.ylabel('$J(C_k)$');

7. Unsupervised Learning: PCA and Clustering

We can see that 7. Unsupervised Learning: PCA and Clustering drops sharply as the number of clusters increases from 1 to 2 and from 2 to 3, and no longer as sharply – when 7. Unsupervised Learning: PCA and Clustering changes from 3 to 4. So for this problem it is optimal to choose 3 clusters.

Complications

Solving the K-means problem itself is NP-hard, and for dimensionality 7. Unsupervised Learning: PCA and Clustering, number of clusters 7. Unsupervised Learning: PCA and Clustering and number of points 7. Unsupervised Learning: PCA and Clustering, it is solved in 7. Unsupervised Learning: PCA and Clustering. To deal with this pain, heuristics are often used, for example MiniBatch K-means, which for training does not use the whole dataset but only small portions of it (batches), and updates the centroids using the average over the entire update history of the centroid from all points assigned to it. A comparison of ordinary K-means and its MiniBatch implementation can be found in the scikit-learn documentation.

The scikit-learn implementation of the algorithm has plenty of handy perks, such as the ability to set the number of runs via the n_init parameter, which gives more stable cluster centroids in the case of skewed data. Moreover, these runs can be done in parallel, without sacrificing computation time.

Affinity Propagation

Another example of a clustering algorithm. Unlike the K-means algorithm, this approach does not require specifying in advance the number of clusters we want to split our data into. The main idea of the algorithm is that we want our observations to be clustered into groups based on how they "communicate", or how similar they are to each other.

For this, let us introduce some "similarity" metric, defined such that 7. Unsupervised Learning: PCA and Clusteringif observation 7. Unsupervised Learning: PCA and Clustering is more similar to observation 7. Unsupervised Learning: PCA and Clustering than to 7. Unsupervised Learning: PCA and Clustering. A simple example of such similarity is the negative squared distance 7. Unsupervised Learning: PCA and Clustering.

Now let us describe the "communication" process itself. To do this, we set up two matrices initialized with zeros, one of which 7. Unsupervised Learning: PCA and Clustering will describe how well the 7. Unsupervised Learning: PCA and Clustering-th observation fits to be a "role model" for the 7. Unsupervised Learning: PCA and Clustering-th observation relative to all other potential "examples", while the second — 7. Unsupervised Learning: PCA and Clustering will describe how correct it would be for the 7. Unsupervised Learning: PCA and Clustering-th observation to choose the 7. Unsupervised Learning: PCA and Clustering-th as such an "example". It sounds a bit confusing, but a little further on we will see an example "in plain terms".

After that these matrices are updated in turn according to the rules:

7. Unsupervised Learning: PCA and Clustering

7. Unsupervised Learning: PCA and Clustering

7. Unsupervised Learning: PCA and Clustering

Spectral clustering

Spectral clustering combines several of the approaches described above to get the maximum profit from complex manifolds of dimensionality lower than the original space.

For this algorithm to work, we will need to define a matrix of observation similarity (adjacency matrix). This can be done the same way as for Affinity Propagation above: 7. Unsupervised Learning: PCA and Clustering. This matrix also describes a complete graph with vertices at our observations and edges between every pair of observations with a weight corresponding to the degree of similarity of these vertices. For our metric chosen above and points lying on a plane, this thing is intuitive and simple — two points are more similar if the edge between them is shorter. Now we would like to split our resulting graph into two parts so that the resulting points in the two graphs are, on the whole, more similar to other points inside their resulting "own" half of the graph than to points in the "other" half. The formal name for such a problem is called the Normalized cuts problem, and you can read more about this here.

Agglomerative clustering

Probably the simplest and most understandable clustering algorithm without a fixed number of clusters — agglomerative clustering. The intuition of the algorithm is very simple:

  1. We start by pouring out a separate cluster onto each point
  2. Sort the pairwise distances between cluster centers in ascending order
  3. Take the pair of closest clusters, merge them into one and recompute the cluster center
  4. Repeat steps 2 and 3 until all the data has merged into a single cluster

The process of finding the closest clusters itself can happen using different methods of merging points:

  1. Single linkage — minimum of the pairwise distances between points from two clusters
    7. Unsupervised Learning: PCA and Clustering
  2. Complete linkage — maximum of the pairwise distances between points from two clusters
    7. Unsupervised Learning: PCA and Clustering
  3. Average linkage — average of the pairwise distances between points from two clusters
    7. Unsupervised Learning: PCA and Clustering
  4. Centroid linkage — distance between the centroids of two clusters
    7. Unsupervised Learning: PCA and Clustering

The profit of the first three approaches compared to the fourth is that for them there is no need to recompute distances every time after merging, which greatly reduces the computational complexity of the algorithm.

Based on the results of running such an algorithm, one can also build a nice tree of cluster merges and, looking at it, determine at which stage it would be most optimal for us to stop the algorithm. Or use the same elbow rule as in k-means.

Fortunately for us, Python already has great tools for building such dendrograms for agglomerative clustering. Let's look at an example using our clusters from K-means:

from scipy.cluster import hierarchy
from scipy.spatial.distance import pdist

X = np.zeros((150, 2))

np.random.seed(seed=42)
X[:50, 0] = np.random.normal(loc=0.0, scale=.3, size=50)
X[:50, 1] = np.random.normal(loc=0.0, scale=.3, size=50)

X[50:100, 0] = np.random.normal(loc=2.0, scale=.5, size=50)
X[50:100, 1] = np.random.normal(loc=-1.0, scale=.2, size=50)

X[100:150, 0] = np.random.normal(loc=-1.0, scale=.2, size=50)
X[100:150, 1] = np.random.normal(loc=2.0, scale=.5, size=50)

distance_mat = pdist(X) # pdist will compute for us the upper triangle of the pairwise distance matrix

Z = hierarchy.linkage(distance_mat, 'single') # linkage — implementation of the agglomerative algorithm
plt.figure(figsize=(10, 5))
dn = hierarchy.dendrogram(Z, color_threshold=0.5)

7. Unsupervised Learning: PCA and Clustering

Clustering quality metrics

The task of assessing clustering quality is more complex compared to assessing classification quality. First, such assessments should not depend on the label values themselves, but only on the partitioning of the sample itself. Second, the true labels of the objects are not always known, so we also need estimates that allow us to assess the quality of clustering using only an unlabeled sample.

There are external and internal quality metrics. External ones use information about the true division into clusters, while internal metrics do not use any external information and assess the quality of clustering based only on the dataset. The optimal number of clusters is usually determined using internal metrics.

All the metrics listed below are implemented in sklearn.metrics.

Adjusted Rand Index (ARI)

It is assumed that the true labels of the objects are known. This measure does not depend on the label values themselves, but only on the partitioning of the sample into clusters. Let 7. Unsupervised Learning: PCA and Clustering — be the number of objects in the sample. Denote by 7. Unsupervised Learning: PCA and Clustering — the number of pairs of objects that have the same labels and are in the same cluster, and by 7. Unsupervised Learning: PCA and Clustering— the number of pairs of objects that have different labels and are in different clusters. Then the Rand Index is

7. Unsupervised Learning: PCA and Clustering


That is, this is the fraction of objects for which these partitions (the original one and the one obtained as a result of clustering) "agree". The Rand Index (RI) expresses the similarity of two different clusterings of the same sample. For this index to give values close to zero for random clusterings for any 7. Unsupervised Learning: PCA and Clustering and number of clusters, it needs to be normalized. This is how the Adjusted Rand Index is defined:

7. Unsupervised Learning: PCA and Clustering

This measure is symmetric and does not depend on the values and permutations of the labels. Thus, this index is a measure of distance between different partitions of the sample. 7. Unsupervised Learning: PCA and Clustering takes values in the range 7. Unsupervised Learning: PCA and Clustering. Negative values correspond to "independent" partitions into clusters, values close to zero — to random partitions, and positive values indicate that the two partitions are similar (they coincide when 7. Unsupervised Learning: PCA and Clustering).

Adjusted Mutual Information (AMI)

This measure is very similar to 7. Unsupervised Learning: PCA and Clustering. It is also symmetric and does not depend on the values and permutations of the labels. It is defined using the entropy function, interpreting the sample partitions as discrete distributions (the probability of assignment to a cluster equals the fraction of objects in it). The 7. Unsupervised Learning: PCA and Clusteringindex is defined as the mutual information for the two distributions corresponding to the partitions of the sample into clusters. Intuitively, mutual information measures the fraction of information common to both partitions: how much information about one of them reduces the uncertainty about the other.

Similarly to 7. Unsupervised Learning: PCA and Clustering, the index 7. Unsupervised Learning: PCA and Clustering is defined, which allows getting rid of the growth of the index 7. Unsupervised Learning: PCA and Clustering with an increasing number of classes. It takes values in the range 7. Unsupervised Learning: PCA and Clustering. Values close to zero indicate independence of the partitions, and values close to one – their similarity (coinciding when 7. Unsupervised Learning: PCA and Clustering).

Homogeneity, completeness, V-measure

Formally, these measures are also defined using the entropy and conditional entropy functions, treating the sample partitions as discrete distributions:

7. Unsupervised Learning: PCA and Clustering


here 7. Unsupervised Learning: PCA and Clustering — is the clustering result, 7. Unsupervised Learning: PCA and Clustering — is the true division of the sample into classes. Thus, 7. Unsupervised Learning: PCA and Clusteringmeasures how much each cluster consists of objects of one class, and 7. Unsupervised Learning: PCA and Clustering — how much objects of one class belong to one cluster. These measures are not symmetric. Both quantities take values in the range 7. Unsupervised Learning: PCA and Clustering, and larger values correspond to more accurate clustering. These measures are not normalized, like 7. Unsupervised Learning: PCA and Clustering or 7. Unsupervised Learning: PCA and Clustering, and therefore depend on the number of clusters. Random clustering will not give zero scores with a large number of classes and a small number of objects. In these cases it is preferable to use 7. Unsupervised Learning: PCA and Clustering. However, with more than 1000 objects and fewer than 10 clusters, this problem is not so pronounced and can be ignored.

To account for both quantities 7. Unsupervised Learning: PCA and Clustering and 7. Unsupervised Learning: PCA and Clustering at the same time, the 7. Unsupervised Learning: PCA and Clustering-measure is introduced, as their harmonic mean:

7. Unsupervised Learning: PCA and Clustering

It is symmetric and shows how similar two clusterings are to each other.

Silhouette

Unlike the metrics described above, this coefficient does not assume knowledge of the true labels of the objects, and allows assessing the quality of clustering using only the (unlabeled) sample itself and the clustering result. First, the silhouette is defined separately for each object. Denote by 7. Unsupervised Learning: PCA and Clustering — the average distance from the given object to objects from the same cluster, and by 7. Unsupervised Learning: PCA and Clustering— the average distance from the given object to objects from the nearest cluster (other than the one the object itself belongs to). Then the silhouette of the given object is defined as the quantity:

7. Unsupervised Learning: PCA and Clustering


The silhouette of the sample is defined as the average value of the silhouette of the objects in the given sample. Thus, the silhouette shows how much the average distance to objects of its own cluster differs from the average distance to objects of other clusters. This quantity lies in the range 7. Unsupervised Learning: PCA and Clustering. Values close to -1 correspond to poor (scattered) clusterings, values close to zero indicate that the clusters overlap and intersect with each other, values close to 1 correspond to "dense", clearly separated clusters. Thus, the larger the silhouette, the more clearly the clusters are separated, and they represent compact, densely grouped clouds of points.

With the help of the silhouette one can choose the optimal number of clusters 7. Unsupervised Learning: PCA and Clustering (if it is not known in advance) — the number of clusters that maximizes the silhouette value is chosen. Unlike the previous metrics, the silhouette depends on the shape of the clusters, and reaches larger values on more convex clusters, obtained using algorithms based on reconstructing the density of the distribution.

And finally, let us look at these metrics for our algorithms, run on the MNIST handwritten digit data:

from sklearn import metrics
from sklearn import datasets
import pandas as pd
from sklearn.cluster import KMeans, AgglomerativeClustering, AffinityPropagation, SpectralClustering

data = datasets.load_digits()
X, y = data.data, data.target

algorithms = []
algorithms.append(KMeans(n_clusters=10, random_state=1))
algorithms.append(AffinityPropagation())
algorithms.append(SpectralClustering(n_clusters=10, random_state=1,
                                     affinity='nearest_neighbors'))
algorithms.append(AgglomerativeClustering(n_clusters=10))

data = []
for algo in algorithms:
    algo.fit(X)
    data.append(({
        'ARI': metrics.adjusted_rand_score(y, algo.labels_),
        'AMI': metrics.adjusted_mutual_info_score(y, algo.labels_),
        'Homogenity': metrics.homogeneity_score(y, algo.labels_),
        'Completeness': metrics.completeness_score(y, algo.labels_),
        'V-measure': metrics.v_measure_score(y, algo.labels_),
        'Silhouette': metrics.silhouette_score(X, algo.labels_)}))

results = pd.DataFrame(data=data, columns=['ARI', 'AMI', 'Homogenity',
                                           'Completeness', 'V-measure', 
                                           'Silhouette'],
                       index=['K-means', 'Affinity', 
                              'Spectral', 'Agglomerative'])

results

ARI AMI Homogenity Completeness V-measure Silhouette
K-means 0.662295 0.732799 0.735448 0.742972 0.739191 0.182097
Affinity 0.175174 0.451249 0.958907 0.486901 0.645857 0.115197
Spectral 0.752639 0.827818 0.829544 0.876367 0.852313 0.182195
Agglomerative 0.794003 0.856085 0.857513 0.879096 0.868170 0.178497

3. Homework

Current homework assignments are announced during the next session of the course; you can follow them in the VK group and in the course repository.

In the demo version of the homework, you are invited to work with Samsung data on recognizing types of human activity. The task is interesting; we will look at it both as a clustering task (forgetting that the sample is labeled) and as a classification task. A Jupyter starter notebook and a web form for answers are provided; the solution can also be found there.

4. Useful resources

  • Open Machine Learning Course. Topic 7. Unsupervised Learning: PCA and Clustering
  • Video recording of the lecture based on this article
  • Translation of this article into English – Medium story
  • article "How to choose a dress using principal component analysis"
  • article "How principal component analysis (PCA) works, explained with a simple example"
  • article "Interesting clustering algorithms, part one: Affinity propagation"
  • article "Interesting clustering algorithms, part two: DBSCAN"
  • overview of clustering methods in the scikit-learn package (in English)
  • Q&A breakdown of PCA with intuition and examples (in English)
  • notebook on k-Means and the EM algorithm in the course by Dmitry Efimov (in English)
  • lecture notes "Unsupervised Learning" in the course by Evgeny Sokolov

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Machine learning"

Terms: Machine learning