2012-03-04 07:43:36 +08:00
|
|
|
"""
|
|
|
|
|
=========================================================
|
|
|
|
|
Comparing different clustering algorithms on toy datasets
|
|
|
|
|
=========================================================
|
|
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
This example shows characteristics of different
|
2012-03-04 07:43:36 +08:00
|
|
|
clustering algorithms on datasets that are "interesting"
|
2017-03-22 06:15:37 +08:00
|
|
|
but still in 2D. With the exception of the last dataset,
|
|
|
|
|
the parameters of each of these dataset-algorithm pairs
|
|
|
|
|
has been tuned to produce good clustering results. Some
|
|
|
|
|
algorithms are more sensitive to parameter values than
|
|
|
|
|
others.
|
|
|
|
|
|
|
|
|
|
The last dataset is an example of a 'null' situation for
|
|
|
|
|
clustering: the data is homogeneous, and there is no good
|
|
|
|
|
clustering. For this example, the null dataset uses the
|
|
|
|
|
same parameters as the dataset in the row above it, which
|
|
|
|
|
represents a mismatch in the parameter values and the
|
|
|
|
|
data structure.
|
|
|
|
|
|
|
|
|
|
While these examples give some intuition about the
|
|
|
|
|
algorithms, this intuition might not apply to very high
|
|
|
|
|
dimensional data.
|
2012-03-04 07:43:36 +08:00
|
|
|
"""
|
2013-02-01 22:04:03 +08:00
|
|
|
print(__doc__)
|
2012-03-04 07:43:36 +08:00
|
|
|
|
2012-03-27 17:01:51 +08:00
|
|
|
import time
|
2017-03-22 06:15:37 +08:00
|
|
|
import warnings
|
2012-03-27 17:01:51 +08:00
|
|
|
|
2012-03-04 07:43:36 +08:00
|
|
|
import numpy as np
|
2014-05-15 04:31:03 +08:00
|
|
|
import matplotlib.pyplot as plt
|
2012-03-04 07:43:36 +08:00
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
from sklearn import cluster, datasets, mixture
|
2012-03-04 21:30:56 +08:00
|
|
|
from sklearn.neighbors import kneighbors_graph
|
2012-09-23 19:58:12 +08:00
|
|
|
from sklearn.preprocessing import StandardScaler
|
2017-03-22 06:15:37 +08:00
|
|
|
from itertools import cycle, islice
|
2012-03-04 07:43:36 +08:00
|
|
|
|
2012-03-26 01:13:16 +08:00
|
|
|
np.random.seed(0)
|
|
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
# ============
|
2012-03-27 17:01:51 +08:00
|
|
|
# Generate datasets. We choose the size big enough to see the scalability
|
|
|
|
|
# of the algorithms, but not too big to avoid too long running times
|
2017-03-22 06:15:37 +08:00
|
|
|
# ============
|
2012-03-27 17:01:51 +08:00
|
|
|
n_samples = 1500
|
2012-03-26 05:43:00 +08:00
|
|
|
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=.5,
|
|
|
|
|
noise=.05)
|
|
|
|
|
noisy_moons = datasets.make_moons(n_samples=n_samples, noise=.05)
|
|
|
|
|
blobs = datasets.make_blobs(n_samples=n_samples, random_state=8)
|
2012-03-26 01:13:16 +08:00
|
|
|
no_structure = np.random.rand(n_samples, 2), None
|
2012-03-04 07:43:36 +08:00
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
# Anisotropicly distributed data
|
|
|
|
|
random_state = 170
|
|
|
|
|
X, y = datasets.make_blobs(n_samples=n_samples, random_state=random_state)
|
|
|
|
|
transformation = [[0.6, -0.6], [-0.4, 0.8]]
|
|
|
|
|
X_aniso = np.dot(X, transformation)
|
|
|
|
|
aniso = (X_aniso, y)
|
|
|
|
|
|
|
|
|
|
# blobs with varied variances
|
|
|
|
|
varied = datasets.make_blobs(n_samples=n_samples,
|
|
|
|
|
cluster_std=[1.0, 2.5, 0.5],
|
|
|
|
|
random_state=random_state)
|
|
|
|
|
|
|
|
|
|
# ============
|
|
|
|
|
# Set up cluster parameters
|
|
|
|
|
# ============
|
|
|
|
|
plt.figure(figsize=(9 * 2 + 3, 12.5))
|
2014-11-17 23:43:08 +08:00
|
|
|
plt.subplots_adjust(left=.02, right=.98, bottom=.001, top=.96, wspace=.05,
|
2014-05-15 10:35:13 +08:00
|
|
|
hspace=.01)
|
2012-03-05 00:51:38 +08:00
|
|
|
|
2012-03-05 00:46:38 +08:00
|
|
|
plot_num = 1
|
2014-11-17 23:43:08 +08:00
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
default_base = {'quantile': .3,
|
|
|
|
|
'eps': .3,
|
|
|
|
|
'damping': .9,
|
|
|
|
|
'preference': -200,
|
|
|
|
|
'n_neighbors': 10,
|
|
|
|
|
'n_clusters': 3}
|
|
|
|
|
|
|
|
|
|
datasets = [
|
|
|
|
|
(noisy_circles, {'damping': .77, 'preference': -240,
|
|
|
|
|
'quantile': .2, 'n_clusters': 2}),
|
|
|
|
|
(noisy_moons, {'damping': .75, 'preference': -220, 'n_clusters': 2}),
|
|
|
|
|
(varied, {'eps': .18, 'n_neighbors': 2}),
|
|
|
|
|
(aniso, {'eps': .15, 'n_neighbors': 2}),
|
|
|
|
|
(blobs, {}),
|
|
|
|
|
(no_structure, {})]
|
|
|
|
|
|
|
|
|
|
for i_dataset, (dataset, algo_params) in enumerate(datasets):
|
|
|
|
|
# update parameters with dataset-specific values
|
|
|
|
|
params = default_base.copy()
|
|
|
|
|
params.update(algo_params)
|
|
|
|
|
|
2012-03-04 07:43:36 +08:00
|
|
|
X, y = dataset
|
2017-03-22 06:15:37 +08:00
|
|
|
|
2012-03-05 00:46:38 +08:00
|
|
|
# normalize dataset for easier parameter selection
|
2012-09-23 19:58:12 +08:00
|
|
|
X = StandardScaler().fit_transform(X)
|
2012-03-05 00:46:38 +08:00
|
|
|
|
2012-03-04 07:43:36 +08:00
|
|
|
# estimate bandwidth for mean shift
|
2017-03-22 06:15:37 +08:00
|
|
|
bandwidth = cluster.estimate_bandwidth(X, quantile=params['quantile'])
|
2012-03-04 07:43:36 +08:00
|
|
|
|
2012-03-05 00:46:38 +08:00
|
|
|
# connectivity matrix for structured Ward
|
2017-03-22 06:15:37 +08:00
|
|
|
connectivity = kneighbors_graph(
|
|
|
|
|
X, n_neighbors=params['n_neighbors'], include_self=False)
|
2012-03-05 00:51:38 +08:00
|
|
|
# make connectivity symmetric
|
|
|
|
|
connectivity = 0.5 * (connectivity + connectivity.T)
|
2012-03-04 21:30:56 +08:00
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
# ============
|
|
|
|
|
# Create cluster objects
|
|
|
|
|
# ============
|
2012-03-26 05:43:00 +08:00
|
|
|
ms = cluster.MeanShift(bandwidth=bandwidth, bin_seeding=True)
|
2017-03-22 06:15:37 +08:00
|
|
|
two_means = cluster.MiniBatchKMeans(n_clusters=params['n_clusters'])
|
|
|
|
|
ward = cluster.AgglomerativeClustering(
|
|
|
|
|
n_clusters=params['n_clusters'], linkage='ward',
|
2015-03-17 01:30:22 +08:00
|
|
|
connectivity=connectivity)
|
2017-03-22 06:15:37 +08:00
|
|
|
spectral = cluster.SpectralClustering(
|
|
|
|
|
n_clusters=params['n_clusters'], eigen_solver='arpack',
|
|
|
|
|
affinity="nearest_neighbors")
|
|
|
|
|
dbscan = cluster.DBSCAN(eps=params['eps'])
|
|
|
|
|
affinity_propagation = cluster.AffinityPropagation(
|
|
|
|
|
damping=params['damping'], preference=params['preference'])
|
|
|
|
|
average_linkage = cluster.AgglomerativeClustering(
|
|
|
|
|
linkage="average", affinity="cityblock",
|
|
|
|
|
n_clusters=params['n_clusters'], connectivity=connectivity)
|
|
|
|
|
birch = cluster.Birch(n_clusters=params['n_clusters'])
|
|
|
|
|
gmm = mixture.GaussianMixture(
|
|
|
|
|
n_components=params['n_clusters'], covariance_type='full')
|
|
|
|
|
|
|
|
|
|
clustering_algorithms = (
|
|
|
|
|
('MiniBatchKMeans', two_means),
|
|
|
|
|
('AffinityPropagation', affinity_propagation),
|
|
|
|
|
('MeanShift', ms),
|
|
|
|
|
('SpectralClustering', spectral),
|
|
|
|
|
('Ward', ward),
|
|
|
|
|
('AgglomerativeClustering', average_linkage),
|
|
|
|
|
('DBSCAN', dbscan),
|
|
|
|
|
('Birch', birch),
|
|
|
|
|
('GaussianMixture', gmm)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for name, algorithm in clustering_algorithms:
|
|
|
|
|
t0 = time.time()
|
2014-02-06 19:51:42 +08:00
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
# catch warnings related to kneighbors_graph
|
|
|
|
|
with warnings.catch_warnings():
|
|
|
|
|
warnings.filterwarnings(
|
|
|
|
|
"ignore",
|
|
|
|
|
message="the number of connected components of the " +
|
|
|
|
|
"connectivity matrix is [0-9]{1,2}" +
|
|
|
|
|
" > 1. Completing it to avoid stopping the tree early.",
|
|
|
|
|
category=UserWarning)
|
|
|
|
|
warnings.filterwarnings(
|
|
|
|
|
"ignore",
|
|
|
|
|
message="Graph is not fully connected, spectral embedding" +
|
|
|
|
|
" may not work as expected.",
|
|
|
|
|
category=UserWarning)
|
|
|
|
|
algorithm.fit(X)
|
2014-11-17 23:43:08 +08:00
|
|
|
|
2012-03-27 17:01:51 +08:00
|
|
|
t1 = time.time()
|
2012-03-26 05:43:00 +08:00
|
|
|
if hasattr(algorithm, 'labels_'):
|
|
|
|
|
y_pred = algorithm.labels_.astype(np.int)
|
|
|
|
|
else:
|
|
|
|
|
y_pred = algorithm.predict(X)
|
2012-03-05 00:51:38 +08:00
|
|
|
|
2017-03-22 06:15:37 +08:00
|
|
|
plt.subplot(len(datasets), len(clustering_algorithms), plot_num)
|
2012-03-05 00:46:38 +08:00
|
|
|
if i_dataset == 0:
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.title(name, size=18)
|
2017-03-22 06:15:37 +08:00
|
|
|
|
|
|
|
|
colors = np.array(list(islice(cycle(['#377eb8', '#ff7f00', '#4daf4a',
|
|
|
|
|
'#f781bf', '#a65628', '#984ea3',
|
|
|
|
|
'#999999', '#e41a1c', '#dede00']),
|
|
|
|
|
int(max(y_pred) + 1))))
|
|
|
|
|
plt.scatter(X[:, 0], X[:, 1], s=10, color=colors[y_pred])
|
|
|
|
|
|
|
|
|
|
plt.xlim(-2.5, 2.5)
|
|
|
|
|
plt.ylim(-2.5, 2.5)
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.xticks(())
|
|
|
|
|
plt.yticks(())
|
|
|
|
|
plt.text(.99, .01, ('%.2fs' % (t1 - t0)).lstrip('0'),
|
2014-05-15 10:35:13 +08:00
|
|
|
transform=plt.gca().transAxes, size=15,
|
|
|
|
|
horizontalalignment='right')
|
2012-03-05 00:46:38 +08:00
|
|
|
plot_num += 1
|
2012-03-04 07:43:36 +08:00
|
|
|
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.show()
|