2024. 1. 5. 19:30ㆍ책/머신러닝 완벽가이드
k-평균 알고리즘
- 군집 중심점이라는 특정한 임의의 지점을 선택해 해당 중심에 가장 가까운 포인트들을 선택하는 군집화 기법
k-평균 동작 process
- 군집화의 기준이 되는 중심을 구성하는 군집화 개수만큼 임의의 위치에 가져다 놓음
- 각 데이터가 가장 가까운 곳에 위치한 중심점에 소속됨
- 소속이 결정되면 군집 중심정르 소속된 데이터의 평균 중심으로 이동
- 각 데이터는 기존에 속한 중심점보다 더 가까운 중심점이 있다면 해당 중심점으로 다시 소속을 변경
- 다시 중심을 소속된 데이터의 평균 중심으로 이동
- 중심점을 이동했는데 데이터의 중심점 소속 변경이 없으면 군집화를 종료. 그렇지 않다면 다시 4번 과정을 거쳐서 소속을 변경하고 이 과정을 반복
장점
- 일반적인 군집화에서 가장 많이 활용되는 알고리즘
- 쉽고 간결
단점
- 거리 기반 알고리즘으로 속성의 개수가 매우 많을 경우 군집화 정확도가 떨어짐(이를 위해 pca로 차원 감소를 적용해야 할 수도 있음)
- 반복 횟수가 많을 경우 수행 시간이 매우 느려짐
- 맷 개의 군집을 선택해야 할지 가이드하기 어려움
하이퍼 파라미터 / 설명
n_clusters | 군집화할 개수(군집 중심점의 개수) |
init | 초기에 군집 중심점의 좌표를 설정할 방식. 보통은 임의로 설정하지 않고 K-Means++ 방식으로 설정 |
max-iter | 최대 반복 횟수(이 횟수 이전에 모든 데이터의 중심점 이동이 없으면 종료) |
from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline
iris = load_iris()
# 보다 편리한 데이터 Handling을 위해 DataFrame으로 변환
irisDF = pd.DataFrame(data=iris.data, columns=['sepal_length','sepal_width','petal_length','petal_width'])
irisDF.head(3)
# 개정판 소스 코드 수정(2019.12.24)
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300,random_state=0)
kmeans.fit(irisDF)
# irisDF['cluster']=kmeans.labels_ 개정 소스코드 변경(2019.12.24)
irisDF['target'] = iris.target
irisDF['cluster']=kmeans.labels_
iris_result = irisDF.groupby(['target','cluster'])['sepal_length'].count()
print(iris_result)
# iris 4개의 속성을 2차원 평면에 그리기 위해 PCA로 2개로 차원 축소
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
pca_transformed = pca.fit_transform(iris.data)
irisDF['pca_x'] = pca_transformed[:,0]
irisDF['pca_y'] = pca_transformed[:,1]
# cluster 값이 0, 1, 2 인 경우마다 별도의 Index로 추출
marker0_ind = irisDF[irisDF['cluster']==0].index
marker1_ind = irisDF[irisDF['cluster']==1].index
marker2_ind = irisDF[irisDF['cluster']==2].index
# cluster값 0, 1, 2에 해당하는 Index로 각 cluster 레벨의 pca_x, pca_y 값 추출. o, s, ^ 로 marker 표시
plt.scatter(x=irisDF.loc[marker0_ind,'pca_x'], y=irisDF.loc[marker0_ind,'pca_y'], marker='o')
plt.scatter(x=irisDF.loc[marker1_ind,'pca_x'], y=irisDF.loc[marker1_ind,'pca_y'], marker='s')
plt.scatter(x=irisDF.loc[marker2_ind,'pca_x'], y=irisDF.loc[marker2_ind,'pca_y'], marker='^')
plt.xlabel('PCA 1')
plt.ylabel('PCA 2')
plt.title('3 Clusters Visualization by 2 PCA Components')
plt.show()
군집화 알고리즘 테스트를 위한 데이터 생성
- 사이킷런의 데이터 생성기 : 여러 개의 클래스에 해당하는 데이터 세트를 만드는데, 하나의 클래스에 여러 개의 군집이 분포될 수 있게 데이터를 생성
make_blobs()
- 개별 군집의 중심점과 표준 편차 제어 기능이 추가됨
- 피처 데이터 세트, 타깃 데이터 세트가 투플로 전환
파라미터 설명
n_samples | 생성할 총 데이터의 개수 (디폴트 = 100) |
n_features | 데이터의 피처 개수 |
centers | init값 |
cluster_std | 생성될 군집 데이터의 표준편차 |
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
%matplotlib inline
# 테스트 데이터 생성
X, y = make_blobs(n_samples=200, n_features=2, centers=3, cluster_std=0.8, random_state=0)
print(X.shape, y.shape)
# y target 값의 분포를 확인
unique, counts = np.unique(y, return_counts=True)
print(unique,counts)
> (200, 2) (200,)
> [0 1 2] [67 67 66]
# DataFrame에 적용
import pandas as pd
clusterDF = pd.DataFrame(data=X, columns=['ftr1', 'ftr2'])
clusterDF['target'] = y
target_list = np.unique(y)
# 각 target별 scatter plot 의 marker 값들.
markers=['o', 's', '^', 'P','D','H','x']
# 3개의 cluster 영역으로 구분한 데이터 셋을 생성했으므로 target_list는 [0,1,2]
# target==0, target==1, target==2 로 scatter plot을 marker별로 생성.
for target in target_list:
target_cluster = clusterDF[clusterDF['target']==target]
plt.scatter(x=target_cluster['ftr1'], y=target_cluster['ftr2'], edgecolor='k', marker=markers[target] )
plt.show()
KMeans 객체를 이용하여 X 데이터를 K-Means 클러스터링 수행 후, 시각화
# KMeans 객체를 이용하여 X 데이터를 K-Means 클러스터링 수행
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=200, random_state=0)
cluster_labels = kmeans.fit_predict(X)
clusterDF['kmeans_label'] = cluster_labels
#cluster_centers_ 는 개별 클러스터의 중심 위치 좌표 시각화를 위해 추출
centers = kmeans.cluster_centers_
unique_labels = np.unique(cluster_labels)
markers=['o', 's', '^', 'P','D','H','x']
# 군집된 label 유형별로 iteration 하면서 marker 별로 scatter plot 수행.
for label in unique_labels:
label_cluster = clusterDF[clusterDF['kmeans_label']==label]
center_x_y = centers[label]
plt.scatter(x=label_cluster['ftr1'], y=label_cluster['ftr2'], edgecolor='k',
marker=markers[label] )
# 군집별 중심 위치 좌표 시각화
plt.scatter(x=center_x_y[0], y=center_x_y[1], s=200, 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)
plt.show()
print(clusterDF.groupby('target')['kmeans_label'].value_counts())
> target kmeans_label
> 0 0 66
> 1 1
> 1 2 67
> 2 1 65
> 2 1
군집 평가
실루엣 분석 : 각 군집 간의 거리가 얼마나 효율적으로 분리되어 있는지 나타냄
- 다른 군집과의 거리는 떨어져 있고 동일 군집끼리의 데이터는 서로 가깝게 잘 뭉쳐 있는 경우 효율적으로 분리 되었다 말할 수 있음
- 실루엣 계수(silhouette coefficient) : 개별 데이터가 가지는 군집화 지표
- 실루엣 계수는 -1~1 사이의 값을 가짐
- 1에 가까울 수록, 근처의 군집과 더 멀리 떨어져 있다는 것
- 0에 가까울 수록, 근처의 군집과 가까워진다는 것
- 값은 아예 다른 군집에 데이터 포인트가 할당되었다는 것
from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
# 실루엣 분석 metric 값을 구하기 위한 API 추가
from sklearn.metrics import silhouette_samples, silhouette_score
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']
irisDF = pd.DataFrame(data=iris.data, columns=feature_names)
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300,random_state=0).fit(irisDF)
irisDF['cluster'] = kmeans.labels_
# iris 의 모든 개별 데이터에 실루엣 계수값을 구함.
score_samples = silhouette_samples(iris.data, irisDF['cluster'])
print('silhouette_samples( ) return 값의 shape' , score_samples.shape)
print(np.mean(silhouette_samples(iris.data, irisDF['cluster'])))
print(silhouette_score(iris.data, irisDF['cluster']))
> silhouette_samples( ) return 값의 shape (150,)
> 0.5528190123564095
> 0.5528190123564095
# irisDF에 실루엣 계수 컬럼 추가
irisDF['silhouette_coeff'] = score_samples
# 모든 데이터의 평균 실루엣 계수값을 구함.
average_score = silhouette_score(iris.data, irisDF['cluster'])
print('붓꽃 데이터셋 Silhouette Analysis Score:{0:.3f}'.format(average_score))
> 붓꽃 데이터셋 Silhouette Analysis Score:0.553
# 군집별 평균 실루엣 계수
print(irisDF.groupby('cluster')['silhouette_coeff'].mean())
> cluster
> 0 0.417320
> 1 0.798140
> 2 0.451105
> Name: silhouette_coeff, dtype: float64
군집별 평균 실루엣 계수의 시각화를 통한 군집 개수 최적화 방법
- 전체 데이터의 평균 실루엣 계수 값이 높다고 해서, 반드시 최적의 군집 개수로 군집화가 잘 됐다고 볼 수 없음
- 특정 군집만 실루엣 계수가 엄청 높고 나머지 군집들은 낮아도, 평균 실루엣 계수 자체는 높게 나올 수 있기 때문
- 좋은 군집의 조건
- 전체 실루엣 계수의 평균값(silhouette_score())은 0~1 사이의 값을 가지며, 1에 가까움
- 하지만 전체 실루엣 계수의 평균값과 더불어, 개별 군집의 평균값의 편차가 크지 않아야 함
- 즉, 개별 군집의 실루엣 계수 평균값이 전체 실루엣 계수 평균값에서 크게 벗어나지 않는 것이 중요
### 여러개의 클러스터링 갯수를 List로 입력 받아 각각의 실루엣 계수를 면적으로 시각화한 함수 작성
def visualize_silhouette(cluster_lists, X_features):
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import math
# 입력값으로 클러스터링 갯수들을 리스트로 받아서, 각 갯수별로 클러스터링을 적용하고 실루엣 개수를 구함
n_cols = len(cluster_lists)
# plt.subplots()으로 리스트에 기재된 클러스터링 수만큼의 sub figures를 가지는 axs 생성
fig, axs = plt.subplots(figsize=(4*n_cols, 10), nrows=2, ncols=n_cols)
# 리스트에 기재된 클러스터링 갯수들을 차례로 iteration 수행하면서 실루엣 개수 시각화
for ind, n_cluster in enumerate(cluster_lists):
# KMeans 클러스터링 수행하고, 실루엣 스코어와 개별 데이터의 실루엣 값 계산.
clusterer = KMeans(n_clusters = n_cluster, max_iter=500, random_state=0)
cluster_labels = clusterer.fit_predict(X_features)
centers = clusterer.cluster_centers_
sil_avg = silhouette_score(X_features, cluster_labels)
sil_values = silhouette_samples(X_features, cluster_labels)
y_lower = 10
axs[0,ind].set_title('Number of Cluster : '+ str(n_cluster)+'\\n' \\
'Silhouette Score :' + str(round(sil_avg,3)) )
axs[0,ind].set_xlabel("The silhouette coefficient values")
axs[0,ind].set_ylabel("Cluster label")
axs[0,ind].set_xlim([-0.1, 1])
axs[0,ind].set_ylim([0, len(X_features) + (n_cluster + 1) * 10])
axs[0,ind].set_yticks([]) # Clear the yaxis labels / ticks
axs[0,ind].set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1])
# 클러스터링 갯수별로 fill_betweenx( )형태의 막대 그래프 표현.
for i in range(n_cluster):
ith_cluster_sil_values = sil_values[cluster_labels==i]
ith_cluster_sil_values.sort()
size_cluster_i = ith_cluster_sil_values.shape[0]
y_upper = y_lower + size_cluster_i
color = cm.nipy_spectral(float(i) / n_cluster)
axs[0,ind].fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_sil_values, \\
facecolor=color, edgecolor=color, alpha=0.7)
axs[0,ind].text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
y_lower = y_upper + 10
# 클러스터링된 데이터 시각화
axs[1,ind].scatter(X_features[:, 0], X_features[:, 1], marker='.', s=30, lw=0, alpha=0.7, \\
c=cluster_labels)
axs[1,ind].set_title("Clustered data")
axs[1,ind].set_xlabel("Feature space for the 1st feature")
axs[1,ind].set_ylabel("Feature space for the 2nd feature")
# 군집별 중심 위치 좌표 시각화
unique_labels = np.unique(cluster_labels)
for label in unique_labels:
center_x_y = centers[label]
axs[1,ind].scatter(x=center_x_y[0], y=center_x_y[1], s=70, color='k', edgecolor='k',
marker='$%d$' % label)
axs[0,ind].axvline(x=sil_avg, color="red", linestyle="--")
# make_blobs 을 통해 clustering 을 위한 4개의 클러스터 중심의 500개 2차원 데이터 셋 생성
from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=500, n_features=2, centers=4, cluster_std=1, \\
center_box=(-10.0, 10.0), shuffle=True, random_state=1)
# cluster 개수를 2개, 3개, 4개, 5개 일때의 클러스터별 실루엣 계수 평균값을 시각화
visualize_silhouette([ 2, 3, 4, 5], X)
#iris 데이터로 실루엣 시각화 분석
from sklearn.datasets import load_iris
iris=load_iris()
visualize_silhouette([ 2, 3, 4,5 ], iris.data)
단점
- 직관적으로 이해하기 쉽지만 각 데이터별로 다른 데이터와의 거리를 반복적으로 계산해야 하므로, 데이터 양이 늘어나면 수행시간이 크게 늘어남
- 메모리 부족 등의 에러가 발생하기 쉬움 (이 경우 군집별로 임의의 데이터를 샘플링 해 실루엣 계수를 평가하는 방안을 고민할 것)
평균 이동
K-평균과 평균 이동의 공통점
- 군집의 중심을 지속적으로 움직이면서 군집화를 수행
K-평균과 평균 이동의 차이점
- K-평균은 중심에 소속된 데이터의 평균 거리 중심으로 이동
- 평균 이동은 데이터가 모여있는 밀도가 가장 높은 곳으로 이동
평균 이동 특징
- 데이터의 분포도를 이용해 군집 중심점을 찾음
- 군집 중심점은 데이터 포인트가 모여있는 곳이라는 생각에서 착안
- 이를 위해 확률 밀도 함수를 이용
- 확률 밀도 함수가 피크인 점(가장 집중적으로 데이터가 모여 있을)을 군집 중심점으로 선정
- 주어진 모델의 확률 밀도 함수를 찾기 위해서 KDE(Kernel Density Estimation)를 이용
- 주변 데이터와의 거리 값을 KDE 함수 값으로 입력한 뒤, 그 반환 값을 현재 위치에서 업데이트하면서 이동하는 방식
KDE(Kernel Density Estimation)
- 커널 함수를 통해 어떤 변수의 확률 밀도 함수를 추정하는 대표적인 방법
- 개별 데이터 각각에, 커널 함수를 적용한 값을 모두 더한 뒤 데이터 건수로 나눠 확률 밀도 함수를 추정
- 확률 밀도 함수 PDF(Probability Density Function)
- 확률 변수의 분포를 나타내는 함수 (정규 분포, 감마 분포, t-분포 등)
- 확률 밀도 함수를 알면 특정 변수가 어떤 값을 갖게 될지에 대한 확률을 알게 되므로, 이를 통해 변수의 특성, 확률 분포 등 변수의 많은 요소를 알 수 있음
- 커널 함수의 예시 : 가우시안 커널 함수 적용
import numpy as np
from sklearn.datasets import make_blobs
from sklearn.cluster import MeanShift
X, y = make_blobs(n_samples=200, n_features=2, centers=3,
cluster_std=0.7, random_state=0)
meanshift= MeanShift(bandwidth=0.8)
cluster_labels = meanshift.fit_predict(X)
print('cluster labels 유형:', np.unique(cluster_labels))
> cluster labels 유형: [0 1 2 3 4 5]
meanshift= MeanShift(bandwidth=1) # bandwidth 변경
cluster_labels = meanshift.fit_predict(X)
print('cluster labels 유형:', np.unique(cluster_labels))
> cluster labels 유형: [0 1 2]
대역폭 h : KDE 형태를 부드럽거나 뾰족한 형태로 평활화(smoothing)하는데 적용
- 작은h 값: 좁고 뾰족한 KDE를 가지며 과적합 되기 쉬움 - 많은 수의 군집 중심점을 가짐
- 큰h 값: 과도하게 평활화된 KDE를 가지며 과소적합 되기 쉬움 - 적은 수의 군집 중심점을 가짐
- bandwidth (=KDE의 h) 값을 작게 할수록 군집 개수가 많아짐
- estimate_bandwidth(X) : 최적의 대역폭 h 찾아줌. 파라미터로 피처 데이터 세트(X) 입력
from sklearn.cluster import estimate_bandwidth
# estimate_bandwidth()로 최적의 bandwidth 계산
bandwidth = estimate_bandwidth(X)
print('bandwidth 값:', round(bandwidth,3))
> bandwidth 값: 1.816
import pandas as pd
clusterDF = pd.DataFrame(data=X, columns=['ftr1', 'ftr2'])
clusterDF['target'] = y
# estimate_bandwidth()로 최적의 bandwidth 계산
best_bandwidth = estimate_bandwidth(X)
meanshift= MeanShift(bandwidth=best_bandwidth)
cluster_labels = meanshift.fit_predict(X)
print('cluster labels 유형:',np.unique(cluster_labels))
> cluster labels 유형: [0 1 2]
- 커널 함수의 예시 : 가우시안 커널 함수 적용
대역폭 h : KDE 형태를 부드럽거나 뾰족한 형태로 평활화(smoothing)하는데 적용import numpy as np from sklearn.datasets import make_blobs from sklearn.cluster import MeanShift X, y = make_blobs(n_samples=200, n_features=2, centers=3, cluster_std=0.7, random_state=0) meanshift= MeanShift(bandwidth=0.8) cluster_labels = meanshift.fit_predict(X) print('cluster labels 유형:', np.unique(cluster_labels)) > cluster labels 유형: [0 1 2 3 4 5] meanshift= MeanShift(bandwidth=1) # bandwidth 변경 cluster_labels = meanshift.fit_predict(X) print('cluster labels 유형:', np.unique(cluster_labels)) > cluster labels 유형: [0 1 2]
- 작은h 값: 좁고 뾰족한 KDE를 가지며 과적합 되기 쉬움 - 많은 수의 군집 중심점을 가짐
- 큰h 값: 과도하게 평활화된 KDE를 가지며 과소적합 되기 쉬움 - 적은 수의 군집 중심점을 가짐
- bandwidth (=KDE의 h) 값을 작게 할수록 군집 개수가 많아짐
- estimate_bandwidth(X) : 최적의 대역폭 h 찾아줌. 파라미터로 피처 데이터 세트(X) 입력
from sklearn.cluster import estimate_bandwidth
# estimate_bandwidth()로 최적의 bandwidth 계산
bandwidth = estimate_bandwidth(X)
print('bandwidth 값:', round(bandwidth,3))
> bandwidth 값: 1.816
import pandas as pd
clusterDF = pd.DataFrame(data=X, columns=['ftr1', 'ftr2'])
clusterDF['target'] = y
# estimate_bandwidth()로 최적의 bandwidth 계산
best_bandwidth = estimate_bandwidth(X)
meanshift= MeanShift(bandwidth=best_bandwidth)
cluster_labels = meanshift.fit_predict(X)
print('cluster labels 유형:',np.unique(cluster_labels))
> cluster labels 유형: [0 1 2]
- 평균 이동의 장점
- 데이터 세트의 형태를 특정 형태로 가정하거나, 특정 분포 기반의 모델로 가정하지 않기 때문에 유연한 군집화 가능
- 이상치의 영향력도 크지 않으며, 미리 군집의 개수를 정하지 않아도 됨
- 평균 이동의 단점
- 수행 시간이 오래 걸리고, bandwidth의 크기에 따른 군집화 영향도가 큼
- 활용
- 컴퓨터 비전 영역에서 많이 사용
- 이미지나 영상 데이터에서, 특정 개체를 구분하거나 움직임을 추적하는데 뛰어난 역할
GMM(Gaussian Mixture Model)
- 군집화를 적용하고자 하는 데이터가, 여러 개의 가우시안 분포를 가진 데이터 집합들이 섞여서 생성된 것이라는 가정하에, 군집화를 수행하는 방식
- 데이터를 여러 개의 가우시안 분포가 섞인 것으로 간주
- 이러한 서로 다른 정규 분포에 기반해 군집화를 수행하는 것이 GMM 군집화 방식
- ex) 1000개의 데이터 세트가 있다면 이를 구성하는 여러 개의 정규 분포 곡선을 추출하고, 개별 데이터가 이 중 어떤 정규 분포에 속하는지 결정하는 방식
이와 같은 방식을 GMM에서는 모수 추정이라고 하는데, 모수 추정은 대표적으로 2가지를 추정하는 것
- 개별 정규 분포의 평균과 분산
- 각 데이터가 어떤 정규 분포에 해당되는지의 확률
→ 이러한 모수 추정을 위해 EM(expectiation and maximization)방법 적용
GMM(Gaussian Mixture Model)
- 군집화를 적용하고자 하는 데이터가, 여러 개의 가우시안 분포를 가진 데이터 집합들이 섞여서 생성된 것이라는 가정하에, 군집화를 수행하는 방식
- 데이터를 여러 개의 가우시안 분포가 섞인 것으로 간주
- 이러한 서로 다른 정규 분포에 기반해 군집화를 수행하는 것이 GMM 군집화 방식
- ex) 1000개의 데이터 세트가 있다면 이를 구성하는 여러 개의 정규 분포 곡선을 추출하고, 개별 데이터가 이 중 어떤 정규 분포에 속하는지 결정하는 방식
이와 같은 방식을 GMM에서는 모수 추정이라고 하는데, 모수 추정은 대표적으로 2가지를 추정하는 것
- 개별 정규 분포의 평균과 분산
- 각 데이터가 어떤 정규 분포에 해당되는지의 확률
→ 이러한 모수 추정을 위해 EM(expectiation and maximization)방법 적용
from sklearn.mixture import GaussianMixture
gmm = GaussianMixture(n_components=3, random_state=0).fit(iris.data)
gmm_cluster_labels = gmm.predict(iris.data)
# 클러스터링 결과를 irisDF 의 'gmm_cluster' 컬럼명으로 저장
irisDF['gmm_cluster'] = gmm_cluster_labels
irisDF['target'] = iris.target
# target 값에 따라서 gmm_cluster 값이 어떻게 매핑되었는지 확인.
iris_result = irisDF.groupby(['target'])['gmm_cluster'].value_counts()
print(iris_result)
> target gmm_cluster
> 0 0 50
> 1 2 45
> 1 5
> 2 1 50
> Name: gmm_cluster, dtype: int64
- n_components: 모델의 총 개수. 군집의 개수를 정하는데 중요한 역할 수행
- fit(피처 데이터 세트), predict(피처 데이터 세트)를 수행해 군집을 결정
# 붓꽃 데이터 세트의 K-평균 군집화를 수행한 결과
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300,random_state=0).fit(iris.data)
kmeans_cluster_labels = kmeans.predict(iris.data)
irisDF['kmeans_cluster'] = kmeans_cluster_labels
iris_result = irisDF.groupby(['target'])['kmeans_cluster'].value_counts()
print(iris_result)
> target kmeans_cluster
> 0 1 50
> 1 0 48
> 2 2
> 2 2 36
> 0 14
> Name: kmeans_cluster, dtype: int64
- kmeans 군집화는 개별 군집의 중심에서 원형의 범위로 데이터를 군집화 하지만, 데이터가 길쭉한 타원형으로 늘어선 경우에 군집화를 잘 수행하지 못함
#**GMM군집화와 K-Means군집화를 비교하기 위해 타원형으로 늘어선 임의의 데이터 세트를 생성**
from sklearn.datasets import make_blobs
# make_blobs() 로 300개의 데이터 셋, 3개의 cluster 셋, cluster_std=0.5 을 만듬.
X, y = make_blobs(n_samples=300, n_features=2, centers=3, cluster_std=0.5, random_state=0)
# 길게 늘어난 타원형의 데이터 셋을 생성하기 위해 변환함.
transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]
X_aniso = np.dot(X, transformation)
# feature 데이터 셋과 make_blobs( ) 의 y 결과 값을 DataFrame으로 저장
clusterDF = pd.DataFrame(data=X_aniso, columns=['ftr1', 'ftr2'])
clusterDF['target'] = y
# 생성된 데이터 셋을 target 별로 다른 marker 로 표시하여 시각화 함.
visualize_cluster_plot(None, clusterDF, 'target', iscenter=False)
#K-Means 군집화 수행
# 3개의 Cluster 기반 Kmeans 를 X_aniso 데이터 셋에 적용
kmeans = KMeans(3, random_state=0)
kmeans_label = kmeans.fit_predict(X_aniso)
clusterDF['kmeans_label'] = kmeans_label
visualize_cluster_plot(kmeans, clusterDF, 'kmeans_label',iscenter=True)
#GMM 군집화 수행
# 3개의 n_components기반 GMM을 X_aniso 데이터 셋에 적용
gmm = GaussianMixture(n_components=3, random_state=0)
gmm_label = gmm.fit(X_aniso).predict(X_aniso)
clusterDF['gmm_label'] = gmm_label
# GaussianMixture는 cluster_centers_ 속성이 없으므로 iscenter를 False로 설정.
visualize_cluster_plot(gmm, clusterDF, 'gmm_label',iscenter=False)
#GMM과 K-Means 군집화 결과 비교
print('### KMeans Clustering ###')
print(clusterDF.groupby('target')['kmeans_label'].value_counts())
print('\\n### Gaussian Mixture Clustering ###')
print(clusterDF.groupby('target')['gmm_label'].value_counts())
[output[
### KMeans Clustering ###
target kmeans_label
0 2 73
0 27
1 1 100
2 0 86
2 14
Name: kmeans_label, dtype: int64
### Gaussian Mixture Clustering ###
target gmm_label
0 2 100
1 1 100
2 0 100
Name: gmm_label, dtype: int64
DBSCAN(밀도 기반 군집화)
- 입실론 주변 영역의 최소 데이터 개수를 포함하는 밀도 기준을 충족시키는 데이터인, 핵심 포인트를 연결하면서 군집화를 구성하는 방식
- 데이터의 분포가 기하학적으로 복잡한 데이터 세트에도 효과적으로 군집화 가능
중요한 파라미터
- 입실론 주변 영역 : 개별 데이터를 중심으로 입실론 반경을 가지는 원형의 영역
- 최소 데이터의 개수 : 개별 데이터의 입실론 주변 영역에 포함되는 타 데이터의 개수
입실론 주변 영역 내에 포함되는 최소 데이터 개수를 충족 시키는가 아닌가에 따라 데이터 포인트를 정의
- 핵심 포인트 : 주변 영역 내에 최소 데이터 개수 이상의 타 데이터를 가지고 있을 경우
- 이웃 포인트 : 주변 영역 내에 위치한 타 데이터
- 경계 포인트 : 주변 영역 내에 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않지만 핵심 포인트를 이웃 포인트로 가지고 있는 데이터
- 잡음 포인트 : 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않으며, 핵심 포인트도 이웃 포인트로 가지고 있지 않는 데이터
DBSCAN의 주요한 초기화 파라미터
eps : 입실론 주변 영역의 반경을 의미
min_samples : 핵심 포인트가 되기 위해 입실론 주변 영역 내에 포함돼야 할 데이터의 최소 개수 의미
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
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
# 군집 레이블이 -1인 것은 노이즈에 속하는 군집을 의미
- 군집 레이블이 -1인 것은 노이즈에 속하는 군집을 의미
- Target 유형이 3가지 인데, 군집이 2개가 됐다고 군집화 효율이 떨어진다는 의미는 아님
#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)
★ 표시는 모두 노이즈 값
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)
[output]
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)
[output]
target dbscan_cluster
0 0 48
-1 2
1 1 44
-1 6
2 1 36
-1 14
Name: dbscan_cluster, dtype: int64
- eps 값을 크게 하면, 반경이 커져 포함하는 데이터가 많아지므로 노이즈 데이터 개수가 작아짐
- min_samples를 크게 하면, 주어진 반경 내에서 더 많은 데이터를 포함시켜야 하므로 노이즈 데이터 개수가 커짐
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)
GMM은 앞 절의 일렬로 늘어선 데이터 세트에서는 효과적으로 군집화 적용이 가능했으나 내부와 외부의 원형이 구성된 더 복잡한 형태의 데이터 세트에서는 군집화가 원하는 방향으로 되지 않았음
# 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)
DBSCAN은 원하는 방향으로 정확히 군집화가 됨
- 결론적으로, K 평균, 평균 이동, GMM으로는 기하학적으로 복잡한 데이터 세트를 효과적으로 군집화하기는 어렵다는 것을 알 수 있음
- 이에 반해, DBSCAN는 데이터의 분포가 기하학적으로 복잡한 데이터 세트에도 효과적으로 군집화가 가능함
'책 > 머신러닝 완벽가이드' 카테고리의 다른 글
분류 (0) | 2024.01.05 |
---|---|
회귀 (1) | 2024.01.05 |
차원축소 (1) | 2023.12.30 |
224~349p (0) | 2023.12.16 |
XGBoost 개념 (0) | 2023.12.05 |