Python での Scikit-Learn を使用した DBSCAN

Python での Scikit-Learn を使用した DBSCAN

概要

あなたはコンサルティング会社でデータサイエンティストとして働いています。 あなたが現在割り当てられているプロジェクトには、最近財務に関するコースを修了した学生からのデータが含まれています。 コースを実施する金融会社は、学生が同じコースを購入するか、別のコースを購入するかに影響を与える共通の要因があるかどうかを理解したいと考えています。 これらの要因を理解することで、会社は学生のプロフィールを作成し、各学生をプロフィール別に分類し、コースのリストを推奨することができます。

さまざまな学生グループのデータを調べると、以下の 1、2、および 3 のように、ポイントの配置が XNUMX つあります。

Python PlatoBlockchain データ インテリジェンスの Scikit-Learn を使用した DBSCAN。垂直検索。あい。

プロット 1 では、紫色の点が半円にまとめられており、その円の内側に大量のピンク色の点があり、その半円の外側にオレンジ色の点が少し集中しており、他のすべての点から離れている XNUMX つの灰色の点があることに注意してください。

プロット 2 には、紫色の点の丸い塊、オレンジ色の点の別の点、および他のすべてから離れた XNUMX つの灰色の点があります。

プロット 3 では、紫、青、オレンジ、ピンクの XNUMX つのポイントの集中と、さらに離れた XNUMX つの灰色のポイントを見ることができます。

では、新入生のデータを理解して類似のグループを判別できるモデルを選択するとしたら、そのようなデータに興味深い結果をもたらすクラスタリング アルゴリズムはありますか?

プロットを説明するとき、次のような用語について言及しました ポイントの塊 および ポイントの集中、すべてのグラフに密度の高い領域があることを示しています。 も参考にしました 円形の および 半円形 直線を引いたり、最も近い点を調べたりするだけでは識別が困難な形状。 さらに、主要なデータ分布から逸脱する可能性が高いいくつかの離れたポイントがあり、より多くの課題または ノイズ グループを決めるとき。

次のようなノイズを除去できる密度ベースのアルゴリズム DBスキャン (D密度Bエージング S寛容 C艶やか Aとの応用 Noise) は、密度の高い領域、丸みを帯びた形状、およびノイズのある状況に適しています。

DBSCANについて

DBSCAN は、研究で最も引用されているアルゴリズムの 1996 つであり、最初の出版物は XNUMX 年に登場し、これは 元の DBSCAN 論文. この論文では、アルゴリズムがどのように非線形空間クラスターを識別し、より高次元のデータを効率的に処理できるかを研究者が示しています。

DBSCAN の背後にある主な考え方は、決められた距離または範囲内にあるポイントの最小数があるということです。 半径 と呼ばれる最も「中心的な」クラスター ポイントから コアポイント. その半径内の点は近傍点であり、その近傍の端にある点は 境界点 or 境界点. 半径または近隣距離と呼ばれます イプシロン地区, ε近傍 または単に ε (ギリシャ文字イプシロンの記号)。

また、決定されたクラスタに属する半径を超え、コア点となる最小数に満たないため、コア点または境界点ではない点がある場合、それらは考慮されます。 ノイズポイント.

これは、XNUMX つの異なるタイプのポイントがあることを意味します。つまり、 , 国境 および ノイズ. さらに、主なアイデアは基本的に半径または距離に基づいていることに注意することが重要です。これにより、DBSCAN は、ほとんどのクラスタリング モデルと同様に、その距離メトリックに依存します。 このメトリックには、ユークリッド、マンハッタン、マハラノビスなどがあります。 したがって、データのコンテキストを考慮した適切な距離メトリックを選択することが重要です。 たとえば、GPS からの走行距離データを使用している場合、マンハッタン距離など、道路のレイアウトを考慮したメトリックを使用すると興味深い場合があります。

Python PlatoBlockchain データ インテリジェンスの Scikit-Learn を使用した DBSCAN。垂直検索。あい。

注: DBSCANはノイズを構成するポイントをマッピングするため、外れ値検出アルゴリズムとしても使用できます。 たとえば、どの銀行取引が不正である可能性があり、不正取引の割合が少ないかを判断しようとしている場合、DBSCAN はそれらのポイントを特定するためのソリューションになる可能性があります。

コア ポイントを見つけるために、DBSCAN は最初にポイントをランダムに選択し、その ε 近傍内のすべてのポイントをマッピングし、選択したポイントの近傍数をポイントの最小数と比較します。 選択したポイントに、ポイントの最小数以上の隣接ポイントがある場合、そのポイントはコア ポイントとしてマークされます。 このコア ポイントとその近傍ポイントが最初のクラスターを構成します。

次に、アルゴリズムは最初のクラスターの各ポイントを調べ、ε 内のポイントの最小数と同じ数またはそれ以上の隣接ポイントがあるかどうかを確認します。 その場合、それらの隣接ポイントも最初のクラスターに追加されます。 このプロセスは、最初のクラスターのポイントが ε 内のポイントの最小数よりも少ない近傍を持つまで続行されます。 その場合、アルゴリズムはそのクラスターへのポイントの追加を停止し、そのクラスターの外側にある別のコア ポイントを特定し、その新しいコア ポイントの新しいクラスターを作成します。

次に、DBSCAN は、XNUMX 番目のクラスターの新しいコア ポイントに接続されたすべてのポイントを見つける最初のクラスター プロセスを、そのクラスターに追加するポイントがなくなるまで繰り返します。 次に、別のコア ポイントに遭遇して XNUMX 番目のクラスターを作成するか、以前に確認していないすべてのポイントを反復処理します。 これらの点がクラスターから ε の距離にある場合、それらはそのクラスターに追加され、境界点になります。 そうでない場合は、ノイズ ポイントと見なされます。

アドバイス: DBSCAN の背後にあるアイデアには、多くの規則と数学的デモンストレーションが含まれています。さらに深く掘り下げたい場合は、上記のリンクにある元の論文を参照してください。

DBSCAN アルゴリズムがどのように機能するかを知ることは興味深いことですが、幸いなことに、Python の Scikit-Learn ライブラリが既に実装されていれば、アルゴリズムをコーディングする必要はありません。

実際にどのように機能するか見てみましょう!

クラスタリングのためのデータのインポート

DBSCAN が実際にどのように機能するかを確認するために、プロジェクトを少し変更して、200 人の顧客のジャンル、年齢、年収、支出スコアを持つ小さな顧客データセットを使用します。

消費スコアの範囲は 0 ~ 100 で、人がショッピング モールでお金を使う頻度を 1 ~ 100 のスケールで表します。 0、彼らは最高の支出者です。

注: データセットをダウンロードできます こちら.

データセットをダウンロードすると、それが CSV (コンマ区切り値) ファイルであることがわかります。 買い物データ.csv、Pandas を使用して DataFrame にロードし、 customer_data 変数:

import pandas as pd path_to_file = '../../datasets/dbscan/dbscan-with-python-and-scikit-learn-shopping-data.csv'
customer_data = pd.read_csv(path_to_file)

データの最初の XNUMX 行を確認するには、次を実行できます。 customer_data.head():

この結果:

 CustomerID Genre Age Annual Income (k$) Spending Score (1-100)
0 1 Male 19 15 39
1 2 Male 21 15 81
2 3 Female 20 16 6
3 4 Female 23 16 77
4 5 Female 31 17 40

データを調べると、顧客 ID 番号、ジャンル、年齢、収入 (k$)、および支出スコアを確認できます。 これらの変数の一部またはすべてがモデルで使用されることに注意してください。 たとえば、使用する場合 Age および Spending Score (1-100) 距離メトリックを使用する DBSCAN の変数として、歪みの導入を避けるためにそれらを共通のスケールにすることが重要です。 Age 年で測定され、 Spending Score (1-100) 範囲は 0 から 100 に制限されています。これは、何らかのデータ スケーリングを実行することを意味します。

また、データの型が一貫しているかどうかを確認し、パンダのを実行して処理する必要がある欠損値があるかどうかを確認することで、スケーリング以外にデータに前処理が必要かどうかを確認することもできます。 info() 方法:

customer_data.info()

これは以下を表示します:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 5 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 CustomerID 200 non-null int64 1 Genre 200 non-null object 2 Age 200 non-null int64 3 Annual Income (k$) 200 non-null int64 4 Spending Score (1-100) 200 non-null int64 dtypes: int64(4), object(1)
memory usage: 7.9+ KB

顧客の特​​徴ごとに 200 個の非 null エントリがあるため、欠損値がないことがわかります。 また、次のように表示されるカテゴリ変数であるため、ジャンル列のみにテキスト コンテンツがあることもわかります。 object、および他のすべての機能は数値であり、タイプ int64. したがって、データ型の一貫性と null 値がないという点で、データはさらに分析する準備ができています。

データの視覚化に進み、DBSCAN で使用するのに興味深い特徴を判断できます。 これらの機能を選択したら、それらをスケーリングできます。

この顧客データセットは、階層型クラスタリングの決定版ガイドで使用されているものと同じです。 このデータ、その探索方法、および距離測定基準について詳しく知るには、以下をご覧ください。 PythonとScikit-Learnを使用した階層的クラスタリングの決定的なガイド!

データの視覚化

シーボーンズを使うことで pairplot()、特徴の組み合わせごとに散布図をプロットできます。 以来 CustomerID は単なる識別であり、機能ではありません。次の方法で削除します drop() プロットする前に:

import seaborn as sns customer_data = customer_data.drop('CustomerID', axis=1) sns.pairplot(customer_data);

これは出力します:

Python PlatoBlockchain データ インテリジェンスの Scikit-Learn を使用した DBSCAN。垂直検索。あい。

によって生み出される機能の組み合わせを見ると、 pairplot、のグラフ Annual Income (k$)   Spending Score (1-100) 約5グループのポイントが表示されているようです。 これは、機能の最も有望な組み合わせのようです。 名前のリストを作成し、 customer_data DataFrame に保存し、選択内容を customer_data 将来のモデルで使用するために再び変数。

selected_cols = ['Annual Income (k$)', 'Spending Score (1-100)']
customer_data = customer_data[selected_cols]

列を選択したら、前のセクションで説明したスケーリングを実行できます。 フィーチャを同じ縮尺にするには、または 標準化する Scikit-Learn の StandardScaler、それを作成し、データを適合させて平均と標準偏差を計算し、平均を引いて標準偏差で割ることでデータを変換します。 これは、 fit_transform() 方法:

from sklearn.preprocessing import StandardScaler ss = StandardScaler() scaled_data = ss.fit_transform(customer_data)

変数はスケーリングされ、単に内容を出力するだけでそれらを調べることができます scaled_data 変数。 または、それらを新しい scaled_customer_data 列名とともに DataFrame を使用し、 head() メソッドをもう一度:

scaled_customer_data = pd.DataFrame(columns=selected_cols, data=scaled_data)
scaled_customer_data.head()

これは出力します:

 Annual Income (k$) Spending Score (1-100)
0 -1.738999 -0.434801
1 -1.738999 1.195704
2 -1.700830 -1.715913
3 -1.700830 1.040418
4 -1.662660 -0.395980 

このデータはクラスタリングの準備ができています! DBSCAN を導入する際に、ポイントの最小数とイプシロンについて言及しました。 モデルを作成する前に、これら XNUMX つの値を選択する必要があります。 それがどのように行われるか見てみましょう。

最小を選択します。 サンプルとイプシロン

DBSCAN クラスタリングのポイントの最小数を選択するには、次のように、データの次元数に XNUMX を加えた数以上でなければならないという経験則があります。

$$
テキスト{分ポイント} >= テキスト{データ次元} + 1
$$

ディメンションはデータフレーム内の列の数です。2 つの列を使用しているため、min. ポイントは 2+1、つまり 3 かそれ以上である必要があります。 この例では、 5分。 ポイント.

$$
text{5 (最小ポイント)} >= text{2 (データ次元)} + 1
$$

ベストプラクティス、業界で認められた標準、および含まれているチートシートを含む、Gitを学習するための実践的で実用的なガイドを確認してください。 グーグルGitコマンドを停止し、実際に 学ぶ それ!

ここで、ε の値を選択するには、次の方法があります。 最近傍 アルゴリズムを使用して、各ポイントの事前定義された数の最も近いポイントの距離を見つけます。 この事前に定義された近隣の数が最小です。 マイナス 1 を選択したポイントです。したがって、この場合、アルゴリズムはデータの各ポイントに対して 5-1、つまり 4 つの最も近いポイントを見つけます。 それらは k ネイバーk 4に等しい。

$$
text{k-neighbors} = text{min. ポイント} – 1
$$

近傍を見つけた後、それらの距離を最大から最小に並べ替え、y 軸の距離と x 軸上の点をプロットします。 プロットを見ると、肘の曲がりに似ている場所と、肘の曲がりが推奨される ε 値であることを示す y 軸の点が見つかります。

Note: ε 値を見つけるためのグラフには、大きくても小さくても XNUMX つ以上の「エルボー ベント」がある可能性があります。その場合、値を見つけてテストし、クラスターを最もよく表す結果を持つものを選択できます。プロットのメトリックを見ることによって。

これらの手順を実行するには、アルゴリズムをインポートしてデータに適合させ、各ポイントの距離とインデックスを抽出します。 kneighbors() 方法:

from sklearn.neighbors import NearestNeighbors
import numpy as np nn = NearestNeighbors(n_neighbors=4) nbrs = nn.fit(scaled_customer_data)
distances, indices = nbrs.kneighbors(scaled_customer_data)

距離を見つけたら、それらを最大から最小に並べ替えることができます。 距離配列の最初の列はそれ自体へのポイント (つまり、すべてが 0) であり、XNUMX 番目の列には最小の距離が含まれ、XNUMX 番目の列よりも距離が大きい XNUMX 番目の列が続きます。 XNUMX 番目の列の値を取得し、それらを distances 変数:

distances = np.sort(distances, axis=0)
distances = distances[:,1] 

ソートされた最小距離が得られたので、インポートできます matplotlib、距離をプロットし、「肘の曲がり」がある場所に赤い線を引きます:

import matplotlib.pyplot as plt plt.figure(figsize=(6,3))
plt.plot(distances)
plt.axhline(y=0.24, color='r', linestyle='--', alpha=0.4) plt.title('Kneighbors distance graph')
plt.xlabel('Data points')
plt.ylabel('Epsilon value')
plt.show();

これが結果です:

Python PlatoBlockchain データ インテリジェンスの Scikit-Learn を使用した DBSCAN。垂直検索。あい。

線を引くと、ε 値がわかることに注意してください。この場合は、 0.24.

最終的に最小点と ε が得られます。 両方の変数を使用して、DBSCAN モデルを作成して実行できます。

DBSCAN モデルの作成

モデルを作成するには、Scikit-Learn からインポートして、 eps 引数、および最小ポイントが mean_samples 口論。 次に、それを変数に格納できます。それを呼び出しましょう dbs スケーリングされたデータに合わせます。

from sklearn.cluster import DBSCAN dbs = DBSCAN(eps=0.24, min_samples=5)
dbs.fit(scaled_customer_data)

このように、DBSCAN モデルが作成され、データでトレーニングされました! 結果を抽出するには、 labels_ 財産。 新しいものを作成することもできます labels 列の scaled_customer_data データフレームを作成し、予測されたラベルで埋めます:

labels = dbs.labels_ scaled_customer_data['labels'] = labels
scaled_customer_data.head()

これが最終結果です。

 Annual Income (k$) Spending Score (1-100) labels
0 -1.738999 -0.434801 -1
1 -1.738999 1.195704 0
2 -1.700830 -1.715913 -1
3 -1.700830 1.040418 0
4 -1.662660 -0.395980 -1

ラベルがあることに注意してください -1 値; これらは ノイズポイント、どのクラスターにも属さないもの。 アルゴリズムが検出したノイズ ポイントの数を知るために、値 -1 がラベル リストに表示される回数を数えることができます。

labels_list = list(scaled_customer_data['labels'])
n_noise = labels_list.count(-1)
print("Number of noise points:", n_noise)

これは出力します:

Number of noise points: 62

62 ポイントの元のデータの 200 ポイントがノイズと見なされたことは既にわかっています。 これは多くのノイズであり、おそらく DBSCAN クラスタリングがクラスタの一部として多くのポイントを考慮していなかったことを示しています。 データをプロットすると、何が起こったのかすぐにわかります。

最初にデータを観察したとき、ポイントのクラスターが 5 つあるように見えました。 DBSCAN が形成したクラスターの数を知るために、-1 ではないラベルの数を数えることができます。 そのコードを書く方法はたくさんあります。 ここでは、DBSCAN が多くのクラスターを検出したデータに対しても機能する for ループを作成しました。

total_labels = np.unique(labels) n_labels = 0
for n in total_labels: if n != -1: n_labels += 1
print("Number of clusters:", n_labels)

これは出力します:

Number of clusters: 6

アルゴリズムがデータに 6 つのクラスターがあり、多くのノイズ ポイントがあると予測したことがわかります。 seaborn の scatterplot:

sns.scatterplot(data=scaled_customer_data, x='Annual Income (k$)', y='Spending Score (1-100)', hue='labels', palette='muted').set_title('DBSCAN found clusters');

この結果:

Python PlatoBlockchain データ インテリジェンスの Scikit-Learn を使用した DBSCAN。垂直検索。あい。

プロットを見ると、DBSCAN がより密に接続されたポイントをキャプチャし、同じクラスターの一部と見なされる可能性のあるポイントがノイズであるか、別の小さなクラスターを形成すると見なされることがわかります。

Python PlatoBlockchain データ インテリジェンスの Scikit-Learn を使用した DBSCAN。垂直検索。あい。

クラスターを強調表示すると、DBSCAN がクラスター 1 を完全に取得する方法に注目してください。これは、ポイント間のスペースが少ないクラスターです。 次に、クラスター 0 と 3 のポイントが近接している部分を取得し、より離れたポイントをノイズと見なします。 また、左下半分のポイントをノイズと見なし、右下のポイントを 3 つのクラスターに分割し、ポイントが互いに接近しているクラスター 4、2、および 5 を再びキャプチャします。

DBSCAN はクラスターの密集した領域をキャプチャするのには優れていましたが、データのより大きなスキームである 5 つのクラスターの境界を識別するにはそれほど優れていなかったという結論に達することができます。 私たちのデータでさらに多くのクラスタリング アルゴリズムをテストすることは興味深いでしょう。 メトリックがこの仮説を裏付けるかどうか見てみましょう。

アルゴリズムの評価

DBSCAN を評価するには、 シルエットスコア 同じクラスターのポイント間の距離とクラスター間の距離が考慮されます。

注: 現在、ほとんどのクラスタリング メトリックは、密度に基づいていないため、DBSCAN の評価に使用するのには適していません。 ここでは、Scikit-learn で既に実装されており、クラスターの形状を調べようとするため、シルエット スコアを使用しています。

より適合した評価を行うには、それを使用するか、 密度ベースのクラスタリングの検証 (DBCV) メトリクス。密度ベースのクラスタリング専用に設計されています。 これで利用可能なDBCVの実装があります GitHubの.

まず、インポートできます silhouette_score 次に、Scikit-Learn から、列とラベルを渡します。

from sklearn.metrics import silhouette_score s_score = silhouette_score(scaled_customer_data, labels)
print(f"Silhouette coefficient: {s_score:.3f}")

これは出力します:

Silhouette coefficient: 0.506

このスコアによると、DBSCAN は約 50% のデータをキャプチャできたようです。

まとめ

DBSCAN の長所と短所

DBSCAN は、非常にユニークなクラスタリング アルゴリズムまたはモデルです。

その利点を見ると、データ内の密集した領域や他から離れた点を拾うのが非常に得意です。 これは、データが特定の形状である必要はなく、密に接続されている限り、他の点で囲まれていてもよいことを意味します。

最小点と ε を指定する必要がありますが、たとえば K-Means のように事前にクラスター数を指定する必要はありません。 高次元データ用に設計されているため、非常に大規模なデータベースでも使用できます。

その欠点については、同じクラスター内の異なる密度をキャプチャできないことがわかっているため、密度の大きな違いには苦労しています. また、距離メトリックとポイントのスケーリングにも依存します。 これは、データが十分に理解されていない場合、スケールの違いや意味をなさない距離メトリックを使用すると、おそらくデータを理解できないことを意味します。

DBSCAN 拡張機能

などの他のアルゴリズムがあります。 階層 DBSCAN (HDBSCAN) および クラスタリング構造を識別する順序付けポイント (OPTICS)、DBSCAN の拡張と見なされます。

通常、HDBSCAN と OPTICS はどちらも、データ内にさまざまな密度のクラスターがあり、選択や初期最小値の影響を受けにくい場合にパフォーマンスが向上します。 ポイントと ε パラメータ。

タイムスタンプ:

より多くの スタックアバス