解析環境セットアップ

In [1]:
%matplotlib inline

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

このページで使うデータセットに関しては、使用する時に乱数で作成することにするので、ここで準備しない。

k-means

クラスタリングを行うためのデータセットを乱数で作成する。ここで作るデータセットのセントロイドを 5 個とし、生成する特徴量を 2 次元にする。

In [2]:
import sklearn.datasets
X, y = sklearn.datasets.make_blobs(n_samples=200, centers=5, n_features=2, random_state=2020)

plt.scatter(X[:,0], X[:,1], c=y)
plt.show()

乱数でデータセットを作成したので、各サンプルの真のラベルはわかっている。本来の教師なし学習のクラスタリングでは、そのラベルが状態でクラスタリングを行うので、kmeans を行う時は、以下のように特徴量のみを使って学習を進める。とりあえず、k=3 でクラスタリングしてみる。

In [3]:
import sklearn.cluster

kmeans = sklearn.cluster.KMeans(n_clusters=3, random_state=2020)
kmeans.fit(X)
Out[3]:
KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
       n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto',
       random_state=2020, tol=0.0001, verbose=0)

学習結果は次のようにして取得できる。

In [4]:
# セントロイドの座標
print(kmeans.cluster_centers_)

# 各サンプルの値
print(kmeans.labels_)
[[ 6.90007929 -6.79368976]
 [-2.74748446 -4.42147891]
 [ 9.89029241  7.39993785]]
[1 1 1 2 1 0 1 1 0 0 0 1 1 1 1 1 1 1 1 0 2 1 1 1 0 0 2 1 1 2 1 1 1 1 0 2 1
 1 0 2 0 0 1 1 0 1 0 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
 0 1 2 1 1 1 1 0 1 0 0 0 0 1 1 2 2 1 1 1 2 0 0 1 1 2 1 0 1 2 1 2 1 1 1 0 2
 1 0 1 1 0 1 2 1 1 1 2 1 0 0 1 2 1 0 1 1 1 0 0 2 2 2 2 0 2 1 1 1 2 2 1 1 2
 0 1 1 1 1 0 1 1 2 1 2 0 2 1 0 2 1 1 0 1 1 2 0 0 2 2 2 2 1 1 2 0 1 1 0 0 1
 1 1 1 1 2 1 2 1 1 1 1 2 1 1 1]
In [5]:
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax1.scatter(X[:,0], X[:,1], c=y)

ax2 = fig.add_subplot(1, 2, 2)
ax2.scatter(X[:,0], X[:,1], c=kmeans.labels_)
ax2.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], c='red', marker='x')

plt.show()

次に、エルボー法を使って最適な k を見積もってみる。

In [6]:
import sklearn.cluster

sse = []

k_candidates = np.linspace(2, 10).astype(int)
for k in k_candidates:
    kmeans = sklearn.cluster.KMeans(n_clusters=k, random_state=0)
    kmeans.fit(X)
    sse.append(kmeans.inertia_)
    

plt.plot(k_candidates, sse)
plt.ylabel('SSE')
plt.xlabel('k')
plt.show()

次にシルエット図を描いてみる。

In [7]:
import sklearn.metrics
import matplotlib


def plot_silhoutte(X, y):
    cl = np.unique(y)
    
    silhouette_idx = sklearn.metrics.silhouette_samples(X, y, metric='euclidean')
    y_upper = 0
    y_lower = 0
    yticks = []
    
    for class_id, class_label in enumerate(cl):
        _silhouette_idx = silhouette_idx[y == class_label]
        _silhouette_idx.sort()
        y_upper = y_upper + len(_silhouette_idx)
        
        plt.barh(range(y_lower, y_upper), _silhouette_idx, height=1)
        
        yticks.append((y_lower + y_upper) / 2)
        y_lower = y_lower + len(_silhouette_idx)
    
    silhouette_idx_mean = np.mean(silhouette_idx)

    plt.axvline(silhouette_idx_mean, color='black', linestyle = '--')
    plt.yticks(yticks)
    plt.ylabel('cluster')
    plt.xlabel('silhouette coefficient')
    plt.show()
    
    
plot_silhoutte(X, y)
In [8]:
import sklearn.cluster

kmeans = sklearn.cluster.KMeans(n_clusters=3, random_state=0)
kmeans.fit(X)

y_pred = kmeans.labels_
plot_silhoutte(X, y_pred)
In [9]:
import sklearn.cluster

kmeans = sklearn.cluster.KMeans(n_clusters=5, random_state=0)
kmeans.fit(X)

y_pred = kmeans.labels_
plot_silhoutte(X, y_pred)

DBSCAN

DBSCAN は scikit-learn の DBSCAN で実行できる。

In [10]:
import sklearn.datasets
import sklearn.cluster

X, y = sklearn.datasets.make_blobs(n_samples=200, centers=5, n_features=2, random_state=2020)

clustering = sklearn.cluster.DBSCAN(eps=2.0, min_samples=3)
clustering.fit(X)

y_pred = clustering.labels_


fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax1.scatter(X[:,0], X[:,1], c=y)

ax2 = fig.add_subplot(1, 2, 2)
ax2.scatter(X[:,0], X[:,1], c=clustering.labels_)

plt.show()

DBSCAN を実行すると、ハイパーパラメーターとして探索半径と最小サンプル数を指定する必要がある。これらのパラメーターを変化させて、クラスタリング結果を確認してみよう。

階層的クラスタリング

階層的クラスタリングは scipy パッケージを使って実行する。性能が一般的によいとされるウォード法で階層的クラスタリングを行ってみる。

In [11]:
import pandas as pd
import scipy.cluster.hierarchy
import sklearn.datasets

X, y = sklearn.datasets.make_blobs(n_samples=200, centers=5, n_features=2, random_state=2020)

# method = 'ward', 'single', 'complete', 'centroid', 'median', ...
hclust = scipy.cluster.hierarchy.linkage(X, method='ward', metric='euclidean')
scipy.cluster.hierarchy.dendrogram(hclust, labels=y)
plt.show()
In [12]:
import pandas as pd
import scipy.cluster.hierarchy
import sklearn.datasets

X, y = sklearn.datasets.make_blobs(n_samples=200, centers=5, n_features=2, random_state=2020)

# method = 'ward', 'single', 'complete', 'centroid', 'median', ...
hclust = scipy.cluster.hierarchy.linkage(X, method='single', metric='euclidean')
scipy.cluster.hierarchy.dendrogram(hclust, labels=y)
plt.show()
In [13]:
import pandas as pd
import scipy.cluster.hierarchy
import sklearn.datasets

X, y = sklearn.datasets.make_blobs(n_samples=200, centers=5, n_features=2, random_state=2020)

# method = 'ward', 'single', 'complete', 'centroid', 'median', ...
hclust = scipy.cluster.hierarchy.linkage(X, method='complete', metric='euclidean')
scipy.cluster.hierarchy.dendrogram(hclust, labels=y)
plt.show()
In [14]:
y_pred = scipy.cluster.hierarchy.fcluster(hclust, 10, criterion='distance')
print(y_pred)
[3 3 3 1 3 2 3 3 2 2 2 3 3 3 3 3 3 3 3 2 1 3 3 3 2 2 1 3 3 1 3 3 3 3 2 1 3
 3 2 1 2 2 3 3 2 3 2 3 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2
 2 3 1 3 3 3 3 2 3 2 2 2 2 3 3 1 1 3 3 3 1 2 2 3 3 1 3 3 3 1 3 1 3 3 3 2 1
 3 2 3 3 3 3 1 3 3 3 1 3 2 2 3 1 3 2 3 3 3 2 2 1 1 1 1 2 1 3 3 3 1 1 3 3 1
 2 3 3 3 3 2 3 3 1 3 1 2 1 3 2 1 3 3 2 3 3 1 2 2 1 1 1 1 3 3 1 2 3 3 2 2 3
 3 3 3 3 1 3 1 3 3 3 3 1 3 3 3]

t-SNE

t-SNE は高次元データを可視化するために使われているアルゴリズムである。数千から数万次元の特徴量を 2 次元にマッピングし、わかりやすく可視化することが可能。ここで、例として MNIST データセットを 2 次元にマッピングしてみる。

In [15]:
import sklearn.datasets

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

print(X.shape)
(1797, 64)

このデータをそのまま PCA を行い、最初の 2 つの主成分を散布図にすると次のようになる。

In [16]:
import sklearn.decomposition

pca= sklearn.decomposition.PCA(n_components=2)
pca.fit(X)

X_pca = pca.transform(X)

plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y)
plt.colorbar()
plt.show()

t-SNE は manifold.TSNE の関数で実行する。計算量が多いため、実行するのに時間がかかる。また、t-SNE のハイパーパラメーターとして perplexity があるので、このパラメーターを 5〜100 の間で動かして、可視化結果を確認してみよう。

In [17]:
import sklearn.manifold

tsne= sklearn.manifold.TSNE(n_components=2, perplexity=5, random_state=2020)
X_tsne = tsne.fit_transform(X)

plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y)
plt.colorbar()
plt.show()
In [18]:
import sklearn.manifold

tsne= sklearn.manifold.TSNE(n_components=2, perplexity=100, random_state=2020)
X_tsne = tsne.fit_transform(X)

plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y)
plt.colorbar()
plt.show()

t-SNE 変換後の座標軸は embedding_ を介してアクセスすることができる。

In [19]:
import sklearn.manifold

tsne= sklearn.manifold.TSNE(n_components=2, perplexity=50, random_state=2020)
tsne = tsne.fit(X)

X_tnse = tsne.embedding_

plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y)
plt.colorbar()
plt.show()

UMAP

UMAP は t-SNE と同様に高次元のデータを可視化するために使われるアルゴリズムである。UMAP は scikit-learn に実装されていないため、これを使うためには別途にパッケージのインストールを行う必要がある。

In [20]:
import umap
digits = sklearn.datasets.load_digits()
X = digits.data
y = digits.target

embedding = umap.UMAP(n_neighbors=10).fit_transform(digits.data)
plt.scatter(embedding[:, 0], embedding[:, 1], c=y)
plt.colorbar()
plt.show()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-20-f181e9dadafa> in <module>
      7 y = digits.target
      8 
----> 9 embedding = umap.UMAP(n_neighbors=10).fit_transform(digits.data)
     10 plt.scatter(embedding[:, 0], embedding[:, 1], c=y)
     11 plt.colorbar()

AttributeError: module 'umap' has no attribute 'UMAP'

上のコードが正しい使い方ですが、でエラーが発生する場合は、次のようなインポート方法を試してください。

In [21]:
import umap.umap_ as umap

embedding = umap.UMAP(n_neighbors=10).fit_transform(digits.data)
plt.scatter(embedding[:, 0], embedding[:, 1], c=y)
plt.colorbar()
plt.show()
In [ ]: