第11章 K-平均法クラスタリング
11.1 K-平均法アルゴリズム
K-平均法とは?
K-平均法 (K-Means) アルゴリズム [Mac67, Llo82] は、データセット内のクラスターを検出するための手法です。
実装がシンプルであり、広く利用されているクラスタリング手法の一つです。
このアルゴリズムでは、データポイントをK個のクラスターに分類し、それぞれのクラスターの中心を反復的に更新することで、
データを適切にグループ化します。
アルゴリズムの手順
K-平均法アルゴリズムは、以下の2つのステップを収束するまで繰り返すことで動作します。
- 各クラスターの中心を計算する
- 各ポイントを最も近い中心のクラスターに再割り当てする
この流れを視覚的に表したのが、以下の図11.1です。
図11.1: K-平均法の1回の反復
クラスターが2つ、ポイントが6つのK-平均法アルゴリズムの1回の反復の様子
各反復で、クラスターの中心 (+) を計算し、各ポイントを最も近い中心のクラスターに再割り当てします。
K-平均法の詳細な処理
- 初期クラスターの設定
- 初めにK個のクラスターを適当に選び、それぞれの中心点 (Centroid) を決定します。
-
この初期化方法によって、結果が異なることがあります。
-
クラスターの中心を計算
-
各クラスターの中心を、そこに属する全ポイントの平均値として再計算します。
-
データポイントの再割り当て
- 各データポイントを、最も近いクラスターの中心に移動させます。
-
つまり、ユークリッド距離が最も小さいクラスターを探し、そのクラスターに所属させます。
-
収束判定
- ポイントの割り当てが前回と変化しなくなるまで、2と3の処理を繰り返します。
クラスターが空になる場合の対処法
場合によっては、クラスターが空になってしまうことがあります。
これを防ぐため、以下のような対策を取ることが一般的です。
- 現在のクラスター内で、最も遠いポイントを空のクラスターに割り当てる
- クラスターの初期化を工夫し、極端な偏りを防ぐ
並列化と最適化
K-平均法アルゴリズムは並列化が可能ですが、以下のような並列化の課題があります。
- クラスター数が少ないと並列スラック (並列処理の効果) が不足する
- ポイントの割り当てが不均衡になる可能性がある
- メモリのキャッシュ効率が低下する (キャッシュラインに無関係なデータが含まれる)
そのため、並列化ではポイントの次元で並列処理を行うことが重要になります。
アルゴリズムの擬似コード
K-平均法アルゴリズムを簡単な擬似コードで表すと、以下のようになります。
1 2 3 4 5 6 |
|
11.3 K-平均法とTBB
TBB(Threading Building Blocks)でのK-平均法アルゴリズムは、Cilk Plusと同様の基本的な構造を持ちますが、いくつかの重要な違いがあります。
主な違い
- 配列表記文: 配列表記はシリアルループとして記述され、ベクトル化の目的ではなく表記の簡潔さが優先されます。これにより、パフォーマンスへの影響はありません。
- ハイパーオブジェクトとTLS: ハイパーオブジェクトはスレッド・ローカル・ストレージ(TLS)に置き換えられ、ローカルビューからグローバルビューへのマージは明示的なループを使って行われます。
- タイル形式(tiling): 並列ループにおいて、タイル(ブロック)ごとにスレッド・ローカル・ビューの処理が行われ、パフォーマンスを最適化します。
スレッド・ローカル・ビューの実装
スレッドローカルビューとは並列処理において各スレッドが独自に持つデータのコピーのこと。
TBBでは、tbb::enumerable_thread_specific
テンプレートを使用してスレッド・ローカル・ビューを実装します。これにより、スレッドは各ビューにアクセスすることができます。
- 初期クラスターの設定
- 初めにK個のクラスターを適当に選び、それぞれの中心点 (Centroid) を決定します。
- この初期化方法によって、結果が異なることがあります。
ビューの作成方法には3つのアプローチがあります:
- デフォルト構築 (
enumerable_thread_specific<T> a;
) - コピー構築 (
enumerable_thread_specific<T> b(x);
) - ファンクターによる構築 (
enumerable_thread_specific<T> c(f);
)
以下のコード例は、TBBでのビューの宣言と使用方法を示しています。
1 2 3 4 5 6 7 8 9 10 11 |
|
ローカルビューのリダクション
ローカルビューのリダクション操作は、可換かつ結合的でなければならず、シリアルループで行うことが多いため、スケーラビリティに課題が生じることがあります。この制限は、TBBのparallel_reduce
テンプレートを使うことで解消できます。
ローカルビューの合計をグローバルビューに累積するための関数は以下のように記述できます。
1 2 3 4 5 6 7 8 |
|
K-平均法の並列化
tbb::parallel_for
を使って、並列でK-平均法の計算を実行します。これにより、各スレッドがサブ範囲ごとにポイントを処理します。
1 2 3 4 5 6 7 8 9 |
|
最適化とパフォーマンス
parallel_for
の明示的なタイル形式は、内ループの最適化に有利である場合に使用します。スレッドローカルビューを効率的にルックアップし、反復処理のパフォーマンスを向上させます。
リスト11.7:最も近いクラスタのインデックスを検出する関数
指定したポイントに最も近いインデックスを検出するルーチン。これはリスト11.1の25行目の_sec_reduce_min_ind
と等価なシリアル表現です。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
例:K-平均法の実装
TBBでのK-平均法アルゴリズムでは、以下のコードを使って反復的にクラスタを計算します。各反復では、ローカルビューをグローバルビューに累積し、新しいクラスタを再計算します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
|
TBBを使用したK-平均法の実装は、Cilk Plusと同様のアーキテクチャを採用しつつ、スレッド・ローカル・ストレージ(TLS)を活用して並列化されています。これにより、大規模データセットに対する高効率なクラスタリングが可能となります。
11.4 まとめ
- K-平均法は簡単に実装できるクラスター分析手法
- 並列化においては、ポイント単位の並列処理が有効
- TBB 実装ではスレッド・ローカル・ストレージを活用し、リダクション処理を最適化