본문 바로가기

대외활동/ABC 지역주도형 청년 취업역량강화 ESG 지원산업

[ABC 220927] 비지도 학습 - DBSCAN

반응형

DBSCAN (Density-based Spatial Clustering of Applications with Noise)

  • DBSCAN 밀도 기반 클러스터링
    • 데이터가 위치하고 있는 공간 밀집도를 기준으로 클러스터를 구분
    • 가지를 중심으로 반지름 R의 공간에 최소 M개의 포인트가 존재하는 점을 코어 포인트(core point)라고 함
    • 반지름 R 안에 다른 코어 포인트가 있는 경우 경계 포인트(border point)라고 함
    • 코어 포인트, 경계 포인트도 속하지 않는 점을 Noise(or outlier)로 분류
    • K-Means와 같이 클러스터의 수를 정하지 않아도 됨 Noise point를 통하여 outlier 검출이 가능
    • 클러스터의 밀도에 따라서 클러스터를 서로 연결하기 때문에 기하학적인 모양을 갖는 군집도 잘 찾을 수 있음

DBSCAN (Density-based Spatial Clustering of Applications with Noise) 예제

  • DBSCAN 서울시 중학교 졸업생의 진로 현황 데이터셋을 사용한 밀도 기반 클러스터링
    • 학교 알리미 공개용 데이터 중 서울시 중학교 졸업생의 진로 현황 데이터셋에서 고등학교 진학률 데이터를 활용하여 속성이 비슷한 중학교끼리 클러스터링
    • 클러스터링한 결과를 지도 시각화

DBSCAN 고등학교 진학률 데이터를 활용한 중학교 군집 분석

문제 정의 : 고등학교 진학률 데이터를 활용한 중학교 DBSCAN 군집 분석 및 지도 시각화

기본 라이브러리 임포트

import pandas as pd
import folium

데이터 준비하기

df = pd.read_excel('/content/2016_middle_shcool_graduates_report.xlsx', index_col=0, header=0, engine='openpyxl')
df.head()

데이터 확인하기

df.info()

# 중학교 위치 지도시각화

mschool_map = folium.Map(location=[37.55,126.98], titles='Stamen Terrain', zoom_start=12)

# 중학교 위치 정보를 CircleMarker로 표시 -> popup는 학교명 -> 필요한 컬럼 -> 위도, 경도, 학교명
for name, lat, lng in zip(df.학교명, df.위도, df.경도) :
  folium.CircleMarker([lat, lng], # 위도, 경도
                      radius = 5, # 반지름
                      color='brown', # 둘레 색상
                      fill=True,
                      fill_color='coral', # 원 안에 색상
                      fill_opactiy= 0.7, # 투명도
                      popup='<pre>'+name+'</pre>').add_to(mschool_map)

mschool_map

데이터 전처리

df['코드'].unique()

# 범주형 데이터 -> Object -> 유형 ['국립', '공립', '사립'], 주야 ['주간'], 지역 25개의 구
# -> 인코딩 -> 라벨링 (숫자로만 바꿔주는 것) -> 성능 -> 원핫인코딩(발전가능)
from sklearn import preprocessing

label_encoder = preprocessing.LabelEncoder()

l_location = label_encoder.fit_transform(df['지역']) # 25 -> 0 ~ 24 
l_code = label_encoder.fit_transform(df['코드']) # array([3, 5, 9]) -> 0, 1, 2 다시 라벨링 (범위 조절)
l_type = label_encoder.fit_transform(df['유형']) # ['국립', '공립', '사립'] -> 0, 1, 2
l_day = label_encoder.fit_transform(df['주야']) # ['주간'] -> 0

# df 새로운 컬럼으로 추가
df['location'] = l_location
df['code'] = l_code
df['type'] = l_type
df['day'] = l_day

df.head()

df.info()

# 클러스터링에 필요한 속성을 선택 ->과학고, 외고국제고, 예고체고, 자사고
columns_list = [9, 10, 11, 13]
X = df.iloc[:, columns_list] # [row_index, columns_index]
X.head()

X = preprocessing.StandardScaler().fit(X).transform(X)
X

DBSCAN 군집 모델 설정

# DBSCAN 모델 설정
from sklearn import cluster

# 한 데이터 포인트에서 eps 거리 안에 데이터가 min_samples 개수만큼 포함되어 있으면 클러스터로 포함
# eps 핵심 포인트를 중심으로 측정되는 유클리디언 거리값
# min_samples : 핵심 포인트를 중심점으로 간주하는 주변 지역의 표본 수 
dbm = cluster.DBSCAN(eps=0.3, min_samples=5)

모델 학습하기

dbm.fit(X)

모델 예측(군집) 확인하기

import numpy as np

np.unique(dbm.labels_)
cluster_label = dbm.labels_

# 예측 경과 데이터프레임 추가
df['Cluster'] = cluster_label
df.tail()
df.head()

# 클러스터 결과 확인
# 각 클러스터의 데이터의 건수
df['Cluster'].value_counts()

# 클러스터 값으로 그룹하고, 그룹별로 내용 출력(5개 출력)
group_cols = [0,1,2] + columns_list # 지역, 학교명, 유형 + cols

grouped = df.groupby('Cluster')
grouped['Cluster'].value_counts()

for index, group in grouped:
  print(' * Cluster :', index)
  print(' * len :', len(group))
  print(group.iloc[:,group_cols].head())
  print('\n')

클러스터링 결과 지도 시각화

# 중학교 위치 지도시각화

Cluster_map = folium.Map(location=[37.55,126.98], titles='Stamen Terrain', zoom_start=12)

colors = {-1:'gray', 0:'coral', 1:'blue', 2:'green', 3:'red', 4:'purple', 5:'orange'}

# 중학교 위치 정보를 CircleMarker로 표시 -> popup는 학교명 -> 필요한 컬럼 -> 위도, 경도, 학교명
for name, lat, lng, clus in zip(df.학교명, df.위도, df.경도, df.Cluster) :
  folium.CircleMarker([lat, lng], # 위도, 경도
                      radius = 5, # 반지름
                      color=colors[clus], # 둘레 색상
                      fill=True,
                      fill_color=colors[clus], # 원 안에 색상
                      fill_opactiy= 0.7, # 투명도
                      popup='<pre>'+name+'</pre>').add_to(Cluster_map)

Cluster_map

LIST