ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [군집화] DBSCAN
    머신러닝 & 딥러닝 2021. 11. 3. 22:02

    DBSCAN (Density Based Spatial Clustering of Applications with Noise)

    • 특정 공간 내에 데이터 밀도 차이를 기반 알고리즘으로 하고 있어서 복잡한 기하학적 분포도를 가진 데이터 세트에 대해서도 군집화를 잘 수행한다.

    • 알고리즘이 데이터 밀도 차이를 자동으로 감지하며 군집을 생성하므로 사용자가 군집 개수를 지정할 수 없다.

    • 데이터의 밀도가 자주 변하거나, 아예 모든 데이터의 밀도가 크게 변하지 않으면 군집화 성능이 떨어진다.

    • 피처의 개수가 많으면 군집화 성능이 떨어진다.

    DBSCAN 구성 요소

    • DBSCAN을 구성하는 가장 중요한 두 파라미터는 입실론(epsilon)으로 표기하는 주변 영역과 이 입실론 주변 영역에 포함되는 최소 데이터의 개수 min points

    • 핵심 포인트 (Core Point): 주변 영역 내에 최소 데이터 개수 이상의 타 데이터를 가지고 있을 경우 해당 데이터를 핵심 포인트라 한다.

    • 이웃 포인트 (Neighbor Point): 주변 영역 내에 위치한 타 데이터를 이웃 포인트라고 한다.

    • 경계 포인트 (Border Point): 주변 영역 내에 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않지만 핵심 포인트를 이웃 포인트로 가지고 있는 데이터를 경계 포인트라고 한다.

    • 잡음 포인트 (Noise Point): 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않으며, 핵심 포인트도 이웃 포인트로 가지고 있지 않는 데이터를 잡음 포인트라고 한다.

    DBSCAN 적용하기 – 붓꽃 데이터 셋

    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()

    sepal_length sepal_width petal_length petal_width target
    0 5.1 3.5 1.4 0.2 0
    1 4.9 3.0 1.4 0.2 0
    2 4.7 3.2 1.3 0.2 0
    3 4.6 3.1 1.5 0.2 0
    4 5.0 3.6 1.4 0.2 0

    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: dbscan_cluster, 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개 컴포넌트로 기존 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의 크기를 증가 한 후 노이즈 확인

    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: dbscan_cluster, dtype: int64
    

    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
    

    DBSCAN 적용하기 – make_circles() 데이터 세트

    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)

    댓글