DBSCAN(Density Based Spatial Clustering of Applications with Noise)
DBSCAN 개요
- DBSCAN은 밀도 기반 군집화의 대표적인 알고리즘이다.
- DBSCAN은 간단하고 직관적인 알고리즘으로 되어있지만 특정 공간 내에 데이터 밀도 차이에 기반하여 데이터의 분포가 기하학적으로 복잡한 데이터셋에도 효과적인 군집화가 가능하다.
- DBSCAN를 구성하는 가장 중요한 두 가지 파라미터:
- 입실론 주변 영역(epsilon): 개별 데이터를 중심으로 입실론 반경을 가지는 원형의 영역
- 최소 데이터 개수(min points): 개별 데이터의 입실론 주변 영역에 포함되는 타 데이터의 개수
- 핵심 포인트(Core Point): 주변 영역 내에 최소 데이터 개수 이상의 타 데이터를 가지고 있을 경우 해당 데이터를 핵심 포인트라고 한다.
- 이웃 포인트(Neighbor Point): 주변 영역 내에 위치한 타 데이터를 이웃 포인트라고 한다,
- 경계 포인트(Border Point): 주변 영역 내에 최소 데이터 개수 이상의 이웃 포인트를 가지고 있진 않지만 핵심 포인트를 이웃 포인트로 가지고 있는 데이터를 경계 포인트라고 한다.
- 잡음 포인트(Noise Point): 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않으며, 핵심 포인트도 이웃 포인트로 가지고 있지 않는 데이터를 잡음 포인트라고 한다.
- DBSCAN은 입실론 주변 영역의 최소 데이터 개수를 포함하는 밀도 기준을 충족시키는 데이터인 핵심포인트를 연결하면서 군집화를 구성하는 방식이다.
- 사이킷런은 DBSCAN 클래스를 통해 알고리즘을 지원한다. 주요 파라미터는 다음과 같다.
- eps: 입실론 주변 영역의 반경
- min_samples: 핵심 포인트가 되기 위해 입실론 주변 영역 내에 포함되어야 할 데이터의 최소 개수
iris 데이터에 DBSCAN 적용하기
In [1]:
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
iris = load_iris()
feature_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
irisdf = pd.DataFrame(data=iris.data, columns=feature_names)
irisdf['target'] = iris.target
In [2]:
from sklearn.cluster import DBSCAN
#일반적으로 eps값으로는 1이하의 값을 설정한다
dbscan = DBSCAN(eps=0.6, min_samples=8, metric='euclidean')
dbscan_labels = dbscan.fit_predict(iris.data)
irisdf['dbscan_cluster'] = dbscan_labels
irisdf['target'] = iris.target
iris_result = irisdf.groupby(['target'])['dbscan_cluster'].value_counts()
print(iris_result)
target dbscan_cluster
0 0 49
-1 1
1 1 46
-1 4
2 1 42
-1 8
Name: dbscan_cluster, dtype: int64
0과 1 외에 특이하게 -1이 군집 레이블로 있다.
-1은 노이즈에 속하는 군집을 의미한다.
따라서, iris 데이터는 DBSCAN에서 0, 1 두 개의 군집으로 군집화됐다.
타겟값의 유형이 3가지인데, 군집이 2개라고 효율이 떨어진단 의미는 아니다.
DBSCAN은 군집의 개수를 알고리즘에 따라 자동 지정하므로 DBSCAN에서 군집 개수를 지정하는 것은 무의미하다.
- DBSCAN으로 군집화한 데이터셋을 2차원 평면에서 표현하기 위해 PCA를 이용해 2개의 피처로 압축시킨 후 시각화해보자
- 앞서 만든 함수인 visualize_cluster_plot 이용
In [3]:
def visualize_cluster_plot(clusterobj, dataframe, label_name, iscenter=True):
if iscenter :
centers = clusterobj.cluster_centers_
unique_labels = np.unique(dataframe[label_name].values)
markers=['o', 's', '^', 'x', '*']
isNoise=False
for label in unique_labels:
label_cluster = dataframe[dataframe[label_name]==label]
if label == -1:
cluster_legend = 'Noise'
isNoise=True
else :
cluster_legend = 'Cluster '+str(label)
plt.scatter(x=label_cluster['ftr1'], y=label_cluster['ftr2'], s=70,\
edgecolor='k', marker=markers[label], label=cluster_legend)
if iscenter:
center_x_y = centers[label]
plt.scatter(x=center_x_y[0], y=center_x_y[1], s=250, color='white',
alpha=0.9, edgecolor='k', marker=markers[label])
plt.scatter(x=center_x_y[0], y=center_x_y[1], s=70, color='k',\
edgecolor='k', marker='$%d$' % label)
if isNoise:
legend_loc='upper center'
else: legend_loc='upper right'
plt.legend(loc=legend_loc)
plt.show()
In [4]:
from sklearn.decomposition import PCA
pca = PCA(n_components=2, random_state=0)
pca_transformed = pca.fit_transform(iris.data)
#PCA 변환값을 ftr1, ftr2 칼럼으로 생성
irisdf['ftr1'] = pca_transformed[:, 0]
irisdf['ftr2'] = pca_transformed[:, 1]
visualize_cluster_plot(dbscan, irisdf, 'dbscan_cluster', iscenter=False)
별표로 표현된 값은 모두 노이즈이다.
PCA을 이용해 2차원으로 표현하면 이상치인 노이즈 데이터가 명확히 드러난다.
- DBSCAN을 적용할 땐 특정 군집 개수로 군집을 강제하지 않는 것이 좋다.
- DBSCAN에 적절한 eps와 min_samples를 통해 최적의 군집을 찾는게 중요하다
- eps값을 크게 하면 반경이 커져 포함하는 데이터가 많아지므로 노이즈 데이터 개수가 적어진다.
- min_samples값을 크게 하면 주어진 반경 내에서 더 많은 데이터를 포함시켜야 하므로 노이즈 데이터 개수가 많아진다. 데이터 밀도가 더 커져야 하는데, 매우 촘촘한 데이터 분포가 아닌 경우 노이즈로 인식하기 때문이다.
In [5]:
#eps값 올리기
dbscan = DBSCAN(eps=0.8, min_samples=8, metric='euclidean')
dbscan_labels = dbscan.fit_predict(iris.data)
irisdf['dbscan_cluster'] = dbscan_labels
irisdf['target'] = iris.target
iris_result = irisdf.groupby(['target'])['dbscan_cluster'].value_counts()
print(iris_result)
visualize_cluster_plot(dbscan, irisdf, 'dbscan_cluster', iscenter=False)
target dbscan_cluster
0 0 50
1 1 50
2 1 47
-1 3
Name: dbscan_cluster, dtype: int64
eps를 0.6에서 0.8로 증가시키면 노이즈 데이터 수가 줄어든다.
노이즈 군집인 -1이 3개밖에 없다.
기존에 eps가 0.6일 때 노이즈로 분류된 데이터셋은 eps반경이 커지면서 Cluster 1에 소속됐다.
이번엔 eps는 0.6으로 유지하고 min_samples를 16으로 늘려보자
In [6]:
#min_samples 늘리기
dbscan = DBSCAN(eps=0.6, min_samples=16, metric='euclidean')
dbscan_labels = dbscan.fit_predict(iris.data)
irisdf['dbscan_cluster'] = dbscan_labels
irisdf['target'] = iris.target
iris_result = irisdf.groupby(['target'])['dbscan_cluster'].value_counts()
print(iris_result)
visualize_cluster_plot(dbscan, irisdf, 'dbscan_cluster', iscenter=False)
target dbscan_cluster
0 0 48
-1 2
1 1 44
-1 6
2 1 36
-1 14
Name: dbscan_cluster, dtype: int64
노이즈 데이터가 기존보다 더 증가했음을 알 수 있다.
make_circles() 데이터로 DBSCAN 적용하기
- 복잡한 기하학적 분포를 가지는 데이터셋에서 DBSCAN와 타 알고리즘을 비교해보자
- make_circles()를 이용해 내부 원과 외부 원 형태로 되어있는 2차원 데이터셋을 만들기
In [7]:
from sklearn.datasets import make_circles
X, y = make_circles(n_samples=1000, shuffle=True, noise=0.05, random_state=0, factor=0.5)
clusterdf = pd.DataFrame(data=X, columns=['ftr1', 'ftr2'])
clusterdf['target'] = y
visualize_cluster_plot(None, clusterdf, 'target', iscenter=False)
먼저 k-means와 GMM은 어떻게 위와 같은 데이터셋을 군집화하는지 확인해보자
In [8]:
#k-means
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=2, max_iter=1000, random_state=0)
kmeans_labels = kmeans.fit_predict(X)
clusterdf['kmeans_cluster'] = kmeans_labels
visualize_cluster_plot(kmeans, clusterdf, 'kmeans_cluster', iscenter=True)
위와 아래 절반으로 군집화됐다.
거리 기반 군집화로는 위와 같이 데이터가 특정한 형태로 지속해서 이어지는 부분을 찾아내기 어렵다.
In [10]:
#GMM
from sklearn.mixture import GaussianMixture
gmm = GaussianMixture(n_components=2, random_state=0)
gmm_label = gmm.fit(X).predict(X)
clusterdf['gmm_cluster'] = gmm_label
visualize_cluster_plot(gmm, clusterdf, 'gmm_cluster', iscenter=False)
GMM도 앞에서 한 것처럼 일렬로 늘어진 데이터셋에서는 효과적으로 군집화를 했으나, 내외부의 원형으로 구성된 더 복잡한 형태의 데이터셋에서는 원하는 방향대로 군집화되지 않는다.
이제 DBSCAN을 적용해보자
In [11]:
#DBSCAN
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=0.2, min_samples=10, metric='euclidean')
dbscan_labels = dbscan.fit_predict(X)
clusterdf['dbscan_cluster'] = dbscan_labels
visualize_cluster_plot(dbscan, clusterdf, 'dbscan_cluster', iscenter=False)
DBSCAN을 적용하여 원하는 방향으로 군집화가 되었다.
'Data Science > 파이썬 머신러닝 완벽 가이드' 카테고리의 다른 글
[sklearn] (48) 자연어처리(NLP, Natural Language Processing)와 텍스트 분석(Text Analytics) (0) | 2023.07.28 |
---|---|
[sklearn] (47) 군집화 실습 - 고객 세그먼테이션(Customer Segmentation) (0) | 2023.07.28 |
[sklearn] (45) 가우시안 혼합 모델, GMM(Gaussian Mixture Model) (0) | 2023.07.25 |
[sklearn] (44) 평균 이동 군집화, Mean Shift, KDE 함수 (0) | 2023.07.25 |
[sklearn] (43) 군집 평가(Cluster Evaluation), 실루엣 계수(Silhouette Score) (0) | 2023.07.19 |