본문 바로가기

TIL

[240409] 클러스터링 분석 - ⑤ DBSCAN (실습)

[파이썬으로 하는 클러스터링 분석 by 강민구 튜터]

 

▶ 이론 내용: [240408] 클러스터링 분석 - ⑤ DBSCAN

 

▶ 실습 코드 - DBSCAN

 

1. 패키지 호출 및 데이터 불러오기 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

from sklearn import datasets
from sklearn.preprocessing import StandardScaler

from sklearn.cluster import DBSCAN
from sklearn.cluster import KMeans

# 데이터셋 불러오기
# 2개의 배열로 이루어져 있어, 각 실수 배열을 data_circle로 라벨 값 배열을 data_circle_label로 따로 저장 
data_circle, data_circle_label = datasets.make_circles(n_samples = 300, noise = 0.01, random_state = 0)

# 데이터 형태 탐색
print(data_circle[:5])
print("-----------")
print(data_circle_label[:5])

 

2. DBSCAN 실습

# 2D Scatter Plot 그려 보기 

import plotly.graph_objs as go 

def scatter_plot_2d_with_label(dataset, labels, title = '2D Scatter Plot'):
    fig = go.Figure()
    for label in set(labels):
        # 각 라벨에 해당하는 데이터만 추출
        # [[-0.59432969  0.51193717] [-0.02822862  0.79544635]] 이런 데이터 형태
        # label 값이 같은 것에 대해서는 0번째(ex. -0.59432969), 1번째(ex. 0.51193717) 인자만 쭉 뽑는다는 뜻
        x_data = dataset[labels == label, 0]
        y_data = dataset[labels == label, 1]

        # scatter plot에 그리기 
        fig.add_trace(go.Scatter(
            x = x_data,
            y = y_data,
            mode = 'markers',
            # dict는 그래픽 요소들의 스타일 및 속성 설정에 사용
            marker = dict(
                size = 10,
                opacity = 0.7,
                line = dict(width = 0.5, color = 'black')
            ),
            name = f'Label {label}'
        ))
    # 그래프 레이아웃 설정
    fig.update_layout(
       title = title,
       xaxis = dict(title = 'X'),
       yaxis = dict(title = 'Y'),
       showlegend = True,
       autosize = False,
       width = 800,
       height = 600
    )
    fig.show()

scatter_plot_2d_with_label(data_circle, data_circle_label)

# DBSCAN을 통한 클러스터링
# https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html
dbscan = DBSCAN(eps=0.1, min_samples=4).fit(data_circle)
y_pred = dbscan.labels_
y_pred[:5]

# DBSCAN 결과 시각화 
scatter_plot_2d_with_label(data_circle, y_pred, title = 'DBSCAN Result')

 

# (Practice) K-means와 결과 비교하기

# 내 풀이 
scaler = StandardScaler()
data_circle_s = scaler.fit_transform(data_circle)

kmeans = KMeans(n_clusters = 2, random_state= 0).fit(data_circle_s)
kmeans_pred = kmeans.labels_

scatter_plot_2d_with_label(data_circle, kmeans_pred, title = 'K-means Result')

# 튜터님 풀이 
kmeans = KMeans(n_clusters=2).fit(data_circle)
y_pred_kmeans = kmeans.labels_

scatter_plot_2d_with_label(data_circle, y_pred_kmeans, title = "Kmeans Result")

 

2. K-NN(K-Nearest Neighbors)를 활용한 적정 eps 값 찾기

from sklearn.neighbors import NearestNeighbors
# https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.NearestNeighbors.html

# minPts 값 4를 K, 즉 n_neighbors 값으로 설정해서 학습  
neighbors = NearestNeighbors(n_neighbors=4).fit(data_circle)

# 실행시키면, 각 개별 포인트의 거리와 각 index 번호가 담긴 2개의 배열이 나옴
distances, indices = neighbors.kneighbors(data_circle)

print(distances[:5])
print("-----------")
print(indices[:5])

 

 

 

# 각 데이터 포인터의 k번째 이웃(이웃 중에 가장 거리가 먼 이웃)과의 거리를 가져옴 
distances = np.sort(distances, axis = 0)[:, -1]
distances[:3]

 

 

# k번째 이웃 간 거리를 라인 그래프로 시각화
sns.lineplot(distances)

# elbow point로 보이는 0.83을 거리로 선정해서 찍어봄
dbscan2 = DBSCAN(eps=0.083, min_samples=4).fit(data_circle)
y_pred2 = dbscan2.labels_

scatter_plot_2d_with_label(data_circle, y_pred2, title = "DBSCAN2 Result")

 

>> KNN 값이 늘 정답인 것은 아니니 한 번 돌려보고 하이퍼 파라미터 값을 조정해 나가는 것이 BEST

>> 레이블이 -1인 값은 Noise Point에 해당