728x90
1. DBSCAN
DBSCAN은 특정 공간 내에 데이터 밀도 차이를 기반 알고리즘으로 하고 있어서
복잡한 기하학적 분포도를 가진 데이터 세트에 대해서도 군집화를 잘 수행함
DBSCAN은 알고리즘이 데이터 밀도 차이를 자동으로 감지하여 군집을 생성하므로 사용자가 군집 개수를 지정할 수 없음
군집화 알고리즘별 비교
- DBSCAN은 데이터의 밀도가 자주 변하거나, 아예 모든 데이터의 밀도가 크게 변하지 않으면 군집화 성능이 떨어짐
- Feature의 개수가 많으면 군집화 성능이 떨어짐
DBSCAN 구성 요소
DBSCAN을 구성하는 가장 중요한 두 가지 파라미터는 입실론(epsilon)으로 표기하는 주변 영역과 이 입실론 주변 영역에 포함되는 최소 데이터의 개수 min points
- 입실론 주변 영역(epsilon): 개별 데이터를 중심으로 입실론 반경을 가지는 원형의 영역
- 최소 데이터 개수(min points): 개별 데이터의 입실론 주변 영역에 포함되는 타 데이터의 개수
Data Points
입실론 주변 영역 내에 포함되는 최소 데이터 개수를 충족시키는가 아닌가에 따라 데이터 포인트를 다음과 같이 정의
해당 Point를 기준으로 Epsilon 반경으로 원형의 영역을 그리고 해당 영역 내 포함되는 최소 데이터 개수를 체크
- Core Point (핵심 포인트)
- 주변 영역 내에 최소 데이터 개수 이상의 타 데이터를 가지고 있을 경우 해당 데이터를 핵심 포인트
- Neighbor Point (이웃 포인트)
- 주변 영역 내에 위치한 타 데이터를 이웃 포인트
- 유동적, 일종의 역할
- Border Point (경계 포인트)
- 주변 영역 내에 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않지만 핵심 포인트를 이웃 포인트로 가지고 있는 데이터를 경계 포인트
- Noise Point (잡음 포인트)
- 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않으며, 핵심 포인트도 이웃 포인트로 가지고 있지 않는 데이터를 잡음 포인트
DBSCAN 절차
12개의 Data Point들에 대해 DBSCAN 군집화 진행
- 1) 특정 입실론 반경 내에 포함될 최소 데이터 세트(min_points)를 6개로 가정 (자기 자신의 데이터를 포함)
- 2) P1 데이터를 기준으로 입실론 반경 내에 포함된 데이터가 7개로 최소 데이터 5개 이상을 만족하므로 P1 데이터는 핵심 포인트
- 3) P2 데이터를 기준으로 입실론 반경 내에 포함된 데이터가 6개로 역시 핵심 포인트
- 4) 핵심 포인트 P1의 이웃 데이터 포인트 P2 역시 핵심 포인트일 경우 P1에서 P2로 연결해 직접 접근이 가능
- 5) 특정 핵심 포인트에서 직접 접근이 가능한 다른 핵심 포인트를 서로 연결하면서 군집화를 구성. 이러한 방식으로 점차적으로 군집(Cluster) 영역을 확장해 나가는 것이 DBSCAN 군집화 방식
- 6) P3 데이터의 경우 반경 내에 포함되는 이웃 데이터는 P2, P4 2개이므로 군집으로 구분할 수 있는 핵심 포인트가 될 수 없음. 하지만 이웃 데이터 중에 핵심 포인트인 P2를 가지고 있음.
- 이처럼 자신은 핵심 포인트가 아니지만, 이웃 데이터로 핵심 포인트를 가지고 있는 데이터를 경계 포인트(Border Point)라고 함.
- 경계 포인트는 군집의 외곽을 형성
- 7) P5와 같이 반경 내에 최소 데이터를 가지고 있지도 않고, 핵심 포인트 또한 이웃 데이터로 가지고 있지 않는 데이터를 잡음 포인트 (Noise Point)라고 함
군집화의 의의
2. DBSCAN @ Scikit - Learn
Scikit - Learn DBSCAN
사이킷런은 DBSCAN 클래스를 통해 DBSCAN 알고리즘을 지원함
DBSCAN 클래스는 다음과 같은 주요한 초기화 파라미터를 가지고 있음
- eps
- 입실론 주변 영역의 반경을 의미함
- min_samples
- 핵심 포인트가 되기 위해 입실론 주변 영역 내에 포함돼야 할 데이터의 최소 개수를 의미함
- 자신의 데이터를 포함, min_points +1
eps를 늘리고 min_samples를 줄이면 밀도가 작음에도 불구하고 군집화를 수행
군집화 개수를 지정할 수 없지만 군집에 해당되는 기준을 완화시킴
3. 실습 - DBSCAN
DBSCAN 적용하기 - iris DataSet
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline
iris = load_iris()
feature_names = ['sepal_length','sepal_width','petal_length','petal_width']
# 보다 편리한 데이타 Handling을 위해 DataFrame으로 변환
irisDF = pd.DataFrame(data=iris.data, columns=feature_names)
irisDF['target'] = iris.target
irisDF.head()
DBSCAN시 Label이 -1일 경우: Noise로 판단 (어떠한 Cluster에도 속하지 않음)
- eps=0.6, min_samples=8로 DBSCAN 군집화 적용
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=0.6, min_samples=8, metric="euclidean")
dbscan_labels = dbscan.fit_predict(iris.data)
irisDF["dbscan_cluster"] = dbscan_labels
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: count, dtype: int64
### 클러스터 결과를 담은 DataFrame과 사이킷런의 Cluster 객체등을 인자로 받아 클러스터링 결과를 시각화하는 함수
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()
- PCA 2개 component로 기존 Feature들을 차원 축소 후 시각화
from sklearn.decomposition import PCA
# 2차원으로 시각화하기 위해 PCA n_componets=2로 피처 데이터 세트 변환
pca = PCA(n_components=2, random_state=0)
pca_transformed = pca.fit_transform(iris.data)
# visualize_cluster_2d( ) 함수는 ftr1, ftr2 컬럼을 좌표에 표현하므로 PCA 변환값을 해당 컬럼으로 생성
irisDF["ftr1"] = pca_transformed[:, 0]
irisDF["ftr2"] = pca_transformed[:, 1]
visualize_cluster_plot(dbscan, irisDF, "dbscan_cluster", iscenter=False)
- eps의 크기를 증가한 후 노이즈 확인
- Noise 감소 (Cluster의 Core Point가 될 수 있는 조건들이 완화)
- 주어진 엡실론 반경 안으로 들어오는 데이터 포인트들이 많아지기 때문
from sklearn.cluster import DBSCAN
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: count, dtype: int64
- min_samples 의 크기를 증가 후 노이즈 화인
- Noise 증가
- Cluster의 Core Point가 되기 위한 조건들이 더 강화
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
DBSCAN 적용하기 - make_circles() 데이터 세트
- make_circles(): 주로 DBSCAN으로 군집화 할 때 사용
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)
# KMeans로 make_circles( ) 데이터 셋을 클러스터링 수행.
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)
# GMM으로 make_circles( ) 데이터 셋을 클러스터링 수행.
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)
# DBSCAN으로 make_circles( ) 데이터 셋을 클러스터링 수행.
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)
728x90