0Pricing
AI Engineering Academy · レッスン

Embeddingのクラスタリングと可視化

一連のembeddingにk-meansクラスタリングを適用し、UMAPを使って2Dで可視化して、データ内の自然なトピックグループを発見します。

「Embeddingのクラスタリングと可視化」はCoddyKit上の無料AI Engineering Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Engineering Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Engineering Academyコースには全4レッスンが含まれています。

埋め込みをクラスタリングする理由

数百、数千件のドキュメントがある場合、すべてを手作業で読むことなく、どのようなトピックが存在するのかを把握したいことがあります。埋め込みのクラスタリングを使うと、意味的に似たドキュメントが自動的にまとめられ、データの自然な構造が明らかになります。

一般的な用途には、サポートチケットへの自動タグ付け、コンテンツカテゴリの発見、重複ドキュメントの検出、ユーザーが最も多く尋ねる内容の把握などがあります。

K-Meansクラスタリングの概要

K-meansは、各データ点を最も近いセントロイドに繰り返し割り当て、その後、割り当てられた点の平均としてセントロイドを再計算することで、n個のデータ点をk個のクラスタに分割します。割り当てが変化しなくなると収束します。

埋め込みに対してk-meansを使うと、高次元の埋め込み空間で近いドキュメントが見つかり、意味的な類似性に基づいてグループ化できます。

from sklearn.cluster import KMeans
import numpy as np

# corpus_embeddings: (n_docs, 1536) — pre-computed
corpus_embeddings = np.random.randn(200, 1536)  # placeholder

kmeans = KMeans(n_clusters=5, random_state=42, n_init='auto')
kmeans.fit(corpus_embeddings)

labels = kmeans.labels_
print(f'Cluster assignments: {labels[:10]}')
print(f'Unique clusters: {set(labels)}')

適切なクラスタ数の選択

k(クラスタ数)の選択が最も難しい部分です。エルボー法では、異なるkの値に対して慣性(セントロイドまでの距離の二乗和)をプロットし、クラスタを増やしても慣性が大きく減少しなくなる点を探します。

シルエットスコアは、ある点が所属クラスタにどれだけ適合しているかを、最も近い別のクラスタへの適合度と比較して測定します。1に近いほど良いスコアです。kを3から20まで試し、最も高いスコアを選びます。

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import numpy as np

corpus_embeddings = np.random.randn(200, 50)  # placeholder (50D for speed)

best_k, best_score = 2, -1
for k in range(2, 11):
    km = KMeans(n_clusters=k, random_state=42, n_init='auto')
    labels = km.fit_predict(corpus_embeddings)
    score = silhouette_score(corpus_embeddings, labels, sample_size=100)
    print(f'k={k}: silhouette={score:.3f}')
    if score > best_score:
        best_score, best_k = score, k

print(f'Best k: {best_k}')

LLMによるクラスタへのラベル付け

クラスタリングの後、各クラスタを代表するドキュメントをいくつかモデルに渡すことで、LLMに人間が読みやすいラベルを生成させることができます。これにより、単なるクラスタ番号が意味のあるカテゴリ名に自動的に変換されます。

from openai import OpenAI

client = OpenAI()

def label_cluster(cluster_docs, n_examples=3):
    examples = '\n'.join(f'- {d}' for d in cluster_docs[:n_examples])
    prompt = f'Given these documents, provide a 3-word category label:\n{examples}\nLabel:'
    response = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        max_tokens=20
    )
    return response.choices[0].message.content.strip()

# Example usage:
# cluster_0_docs = [documents[i] for i in range(len(documents)) if labels[i] == 0]
# print(label_cluster(cluster_0_docs))

UMAPによる次元削減

1536次元のベクトルをそのままプロットすることはできません。UMAP(Uniform Manifold Approximation and Projection)は、局所的な近傍構造を保ちながら、高次元データを2次元または3次元に削減します。PCAとは異なり、UMAPは非線形で、クラスタの構造をより適切に保持できます。

似たドキュメントが2次元プロット上でも近くに残るため、UMAPはテキスト埋め込みの可視化における標準的な選択肢です。

import umap
import numpy as np

corpus_embeddings = np.random.randn(200, 1536)  # placeholder

reducer = umap.UMAP(
    n_components=2,
    metric='cosine',   # important for text embeddings
    random_state=42
)

embeddings_2d = reducer.fit_transform(corpus_embeddings)
print(f'Reduced shape: {embeddings_2d.shape}')  # (200, 2)

Matplotlibによるクラスタの可視化

UMAPから2次元座標を取得し、k-meansからクラスタラベルを取得したら、単純な散布図でクラスタ構造を可視化できます。各点をクラスタラベルに応じて色分けし、代表的なドキュメントのタイトルをテキスト注釈として追加すると、グラフを解釈しやすくなります。

import matplotlib.pyplot as plt
import numpy as np

# Assume: embeddings_2d (n, 2), labels (n,), documents list
# Placeholder data:
np.random.seed(42)
embeddings_2d = np.random.randn(50, 2)
labels = np.random.randint(0, 5, 50)

fig, ax = plt.subplots(figsize=(10, 7))
scatter = ax.scatter(
    embeddings_2d[:, 0],
    embeddings_2d[:, 1],
    c=labels,
    cmap='tab10',
    s=60,
    alpha=0.8
)
plt.colorbar(scatter, label='Cluster')
ax.set_title('Document Embedding Clusters (UMAP)')
plt.tight_layout()
plt.savefig('/tmp/clusters.png', dpi=150)
print('Saved cluster plot')

重要なUMAPパラメーター

可視化の品質に影響する主なUMAPハイパーパラメーター:

  • n_neighbors(デフォルト15):大きい値ではよりグローバルな構造を捉え、小さい値では局所的なクラスタを明らかにします
  • min_dist(デフォルト0.1):点をどれだけ密集させるかを指定します。小さいほどクラスタは密になりますが、クラスタ間の重なりが増えます
  • metric:テキスト埋め込みには必ず'cosine'を使用してください。ユークリッド距離は適切ではありません

n_neighborsを5~50の範囲で試し、データの構造を最もよく表せる可視化を見つけてください。

階層的クラスタリングという選択肢

凝集型階層的クラスタリングは、あらかじめkを指定しなくても、入れ子になったクラスタのツリーを構築します。選択した距離のしきい値でツリーを切ると、最終的なクラスタを得られます。データに自然なトピックがいくつあるか分からない場合に便利です。

from sklearn.cluster import AgglomerativeClustering
import numpy as np

corpus_embeddings = np.random.randn(100, 50)  # placeholder

cluster = AgglomerativeClustering(
    n_clusters=None,
    distance_threshold=1.5,
    metric='cosine',
    linkage='average'
)
labels = cluster.fit_predict(corpus_embeddings)

n_clusters = len(set(labels))
print(f'Found {n_clusters} natural clusters')

外れ値とほぼ重複するドキュメントの検出

埋め込みはほぼ重複するドキュメントの検出にも非常に適しています。すべてのドキュメント間でペアごとのコサイン類似度を計算し、類似度が0.95を超えるペアを重複候補として抽出します。言い換えられた重複も検出できるため、テキストの差分比較より堅牢です。

import numpy as np

def find_near_duplicates(corpus_vecs, threshold=0.95):
    # corpus_vecs assumed L2-normalized
    sim_matrix = corpus_vecs @ corpus_vecs.T  # (n, n)
    duplicates = []
    n = len(corpus_vecs)
    for i in range(n):
        for j in range(i + 1, n):
            if sim_matrix[i, j] >= threshold:
                duplicates.append((i, j, float(sim_matrix[i, j])))
    return duplicates

# pairs = find_near_duplicates(corpus_embeddings)
# print(f'Found {len(pairs)} near-duplicate pairs')

実践的なクラスタリングのワークフロー

実際のクラスタリングワークフローは、次の手順で進めます。

  1. すべてのドキュメントをtext-embedding-3-smallで埋め込む
  2. 必要に応じて、クラスタリング前にUMAPで50次元に削減する(k-meansを高速化できます)
  3. k-meansでクラスタリングし、kを変えながら最適なシルエットスコアを探す
  4. 代表的なドキュメントを5件使い、LLMで各クラスタにラベルを付ける
  5. クラスタごとに色分けした2次元UMAP散布図を可視化する
  6. 外れ値(どのセントロイドからも遠い点)を確認する

クラスタリングの制限

埋め込みのクラスタリングには、把握しておくべき重要な制限があります。

  • K-meansは球状のクラスタを仮定します — 細長い形状や不規則な形状のトピックグループは、誤って分割される可能性があります
  • 埋め込みは意味を圧縮します — 2つのドキュメントが意味的には近くても、実際の対応が異なるカテゴリに属する場合があります
  • クラスタラベルには検証が必要です — LLMが生成したラベルを常識的な観点から確認するため、必ず各クラスタからドキュメントをいくつか抽出してください

クラスタリングは探索のためのツールとして使用し、正解となるカテゴリ分類システムとして扱わないでください。

クイックチェック

このレッスンで学んだAIエンジニアリングの概念を理解できているか確認しましょう。

レッスンのまとめ

このレッスンでは、次のことを学びました。k-meansは埋め込み空間における意味的な近さによって文書をグループ化する、UMAPはコサイン距離を使って高次元の埋め込みを可視化用の2次元に削減する、そしてシルエットスコアはラベル付きデータなしで適切なクラスタ数を選ぶのに役立つということです。次はインメモリ検索の先に進み、本番環境向けのベクトルデータベースを見ていきます。

よくある質問

「Embeddingのクラスタリングと可視化」レッスンは無料ですか?

はい。「Embeddingのクラスタリングと可視化」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Engineering Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Engineering Academyコースには全4レッスンが含まれています。

「Embeddingのクラスタリングと可視化」で何を学びますか?

一連のembeddingにk-meansクラスタリングを適用し、UMAPを使って2Dで可視化して、データ内の自然なトピックグループを発見します。 ブラウザで直接実行するハンズオンコードでAI Engineering Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Engineering Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Engineering Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「Embeddingのクラスタリングと可視化」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Engineering Academyレッスンでコードを書いて実行できますか?

はい。すべてのAI Engineering Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Vector Embeddingとは何か
  2. OpenAIでEmbeddingを生成する
  3. NumPyによるSemantic Search
  4. Embeddingのクラスタリングと可視化
← AI Engineering Academyに戻る