Machine Learning/Advanced (hands on machine learning)

30. 비지도학습 - DBSCAN

jwjwvison 2021. 5. 30. 11:22

 이 알고리즘은 밀집된 연속적 지역을 클러스터로 정의한다. 작동 방식은 다음과 같다.

 이 알고리즘은 모든 클러스터가 충분히 밀집되어 있고 밀집되지 않은 지역과 잘 구분될 때 좋은 성능을 낸다.

from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons

X,y=make_moons(n_samples=1000,noise=0.05)
dbscan=DBSCAN(eps=0.05,min_samples=5)
dbscan.fit(X)

 

 모든 샘플의 레이블은 인스턴스 변수 labels_에 저장되어 있다.

 

 일부 샘플의 클러스터 인덱스는 -1이다. 이는 알고리즘이 이 샘플을 이상치로 판단했다는 의미이다. 핵심 샘플의 인덱스는 인스턴스 변수 core_sample_indices_ 에서 확인할 수 있다. 핵심 샘플 자체는 인스턴스 변수 components_에 저장되어 있다.

len(dbscan.core_sample_indices_)

dbscan.core_sample_indices_

dbscan.components_

 

 DBSCAN 클래스는 fit_predict() 메서드를 제공한다. 다시 말해 이 알고리즘은 새로운 샘플에 대해 클러스터를 예측할 수 없다. 이런 구현 결정은 다른 분류 알고리즘이 이런 작업을 더 잘 수행할 수 있기 때문이다. 따라서 사용자가 필요한 예측기를 선택해야 한다. 예를 들어 KNeighborsClassifer를 훈련해보자.

from sklearn.neighbors import KNeighborsClassifier

knn=KNeighborsClassifier(n_neighbors=50)
knn.fit(dbscan.components_,dbscan.labels_[dbscan.core_sample_indices_])

 

 이제 샘플 몇 개를 전달하여 어떤 클러스터에 속할 가능성이 높은지 예측하고 각 클러스터에 대한 확률을 추정해보자.

import numpy as np
X_new=np.array([[-0.5,0],[0,0.5],[1,-0.1],[2,1]])
knn.predict(X_new)

knn.predict_proba(X_new)

 

 이 결정 경계가 다음 그림에 나타나있다. (덧셈 기호는 X_new에 있는 샘플 네 개를 표시한다). 훈련 세트에 이상치가 없기 때문에 클러스터가 멀리 떨어져 있더라도 분류기는 항상 클러스터 한 개를 선택한다. 최대 거리를 사용하면 두 클러스터에서 멀리 떨어진 샘플을 이상치로 간단히 분류할 수 있다. KNeighborsClassifier 의 Kneighbors() 메서드를 사용한다. 이 메서드에 샘플을 전달하면 훈련 세트에서 가장 가까운 k개 이웃의 거리와 인덱스를 반환한다.(k개 열을 가진 행렬 두 개를 반환한다).

y_dist,y_pred_idx=knn.kneighbors(X_new,n_neighbors=1)
y_pred=dbscan.labels_[dbscan.core_sample_indices_][y_pred_idx]
y_pred[y_dist > 0.2] = -1
y_pred.ravel()

 

 간단히 말해 DBSCAN은 매우 간단하지만 강력한 알고리즘이다. 클러스터의 모양과 개수에 상관없이 감지할 수 있는 능력이 있다. 이상치에 안정적이고 하이퍼파라미터가 두 개뿐이다(eps와 min_samples), 하지만 클러스터 간의 밀집도가 크게 다르면 모든 클러스터를 올바르게 잡아내는 것이 불가능하다. 계산 복잡도는 대략 O(mlogm)이다. 샘플 개수에 대해 거의 선형적으로 증가한다. 하지만 사이킷런의 구현은 eps가 커지면 O(m^2)만큼 메모리가 필요하다.