본문 바로가기
LG 헬로비전 DX DATA SCHOOL/Python

(Python)군집 분석 및 과일 이미지 군집 분석 실습

by 황밤 2023. 9. 1.
728x90
반응형

2023-0901

** Clustering(군집)

 

1. 군집

  • 비슷한 샘플들을 구별해서 하나의 클러스터로 묶는 작업
  • 비지도 학습 : 레이블이 없는 학습 (정답이 없는 학습)


1.1) 군집이 이용되는 분야

  • 고객 분류
  • 데이터 분석 : 각 클러스터로 나눈 후 따로 분석
  • 차원 축소
  • 이상치 탐색 : 모든 클러스터에 친화적이지 않은 데이터를 이상치로 간주
  • 준 지도 학습 : 레이블이 일부분만 존재하는 경우 군집을 수행해서 레이블을 생성
  • 검색 엔진


1.2) 이미지 분할

 

  • sklearn 에서는 다양한 유형의 군집화 알고리즘을 테스트 해보기 위한 샘플 데이터를 생성하는 API 를 제공
make_blobs(), make_classification, make_circle(), make_moon()
군집을 얼마나 효율적으로 했는지 확인하기 위한 target 을 같이 생성

1.3) 군집 실습 데이터 생성

#데이터 생성
from sklearn.datasets import make_blobs

X, y = make_blobs(n_samples=200, n_features=2, centers=3, cluster_std=0.8, random_state=42)
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
clusterDF.head(3)
#3개의 집단으로 군집
from sklearn.mixture import GaussianMixture
y_pred = GaussianMixture(n_components=3, random_state=42).fit(X).predict(X)
print(y_pred)
print(y)

 

#매핑된 결과 확인
from scipy import stats
mapping={}
for class_id in np.unique(y):
    mode, _ = stats.mode(y_pred[y == class_id])
    mapping[mode[0]] = class_id
    
print(mapping)


## {1: 0, 2: 1, 0: 2}
#데이터 분포 확인
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()

 

2. 과일 이미지 군집

  • 과일 이미지 파일 : fruits_300.npy(npy 는 numpy 배열을 저장한 파일)

# 이미지 출력

fruits = np.load('./fruits_300.npy')

print(fruits.shape)
# 3차원이면 흑백, 4차원이면 컬러가 있는 것임.

print(fruits[0, 0, :])

plt.imshow(fruits[0], cmap='gray')
plt.show()

fig, axs = plt.subplots(1, 2)
axs[0].imshow(fruits[100], cmap='gray_r')
axs[1].imshow(fruits[200], cmap='gray_r')
plt.show()

#이미지 데이터를 비교하기 위해서 1차원으로 변경
apple = fruits[0:100].reshape(-1, 100*100)
pineapple = fruits[100:200].reshape(-1, 100*100)
banana = fruits[200:300].reshape(-1, 100*100)

print(apple.shape)
# or
#print(fruits[0].flatten())
#차원 축소 다른 방법

차원 축소 후, 평균 출력

plt.hist(np.mean(apple, axis=1), alpha=0.8)
plt.hist(np.mean(pineapple, axis=1), alpha=0.8)
plt.hist(np.mean(banana, axis=1), alpha=0.8)
plt.legend(['apple', 'pineapple', 'banana'])
plt.show()

#픽셀 단위 출력
fig, axs = plt.subplots(1, 3, figsize=(20, 5))
axs[0].bar(range(10000), np.mean(apple, axis=0))
axs[1].bar(range(10000), np.mean(pineapple, axis=0))
axs[2].bar(range(10000), np.mean(banana, axis=0))
plt.show()

 

#평균을 가지고 이미지 출력

apple_mean = np.mean(apple, axis=0).reshape(100, 100)
pineapple_mean = np.mean(pineapple, axis=0).reshape(100, 100)
banana_mean = np.mean(banana, axis=0).reshape(100, 100)

fig, axs = plt.subplots(1, 3, figsize=(20, 5))
axs[0].imshow(apple_mean, cmap='gray_r')
axs[1].imshow(pineapple_mean, cmap='gray_r')
axs[2].imshow(banana_mean, cmap='gray_r')
plt.show()

#평균값과 가장 가까운 사진 고르기
abs_diff = np.abs(fruits - apple_mean)
abs_mean = np.mean(abs_diff, axis=(1,2))
print(abs_mean.shape)

apple_index = np.argsort(abs_mean)[:100]
fig, axs = plt.subplots(10, 10, figsize=(10,10))
for i in range(10):
    for j in range(10):
        axs[i, j].imshow(fruits[apple_index[i*10 + j]], cmap='gray_r')
        axs[i, j].axis('off')
plt.show()

  • 비슷한 샘플끼리 묶는 것이 군집(clustering)
  • 묶인 그룹을 cluster 라고 합니다.

3. k-Means

3.1) 개요

  • 몇 번의 반복으로 데이터 세트를 빠르고 효율적으로 클러스터링하는 알고리즘
  • PCM(Pulse - Code Modulation)을 구현하기 위해서 등장

3.2) 알고리즘

  • 무작위로 centroid를 선정
  • 각 데이터들을 각 centroid에 배정
  • 배정된 데이터들의 거리가 최소가 되도록 centorid를 수정해서 다시 데이터들을 할당
  • centroid가 더 이상 변경되지 않으면 종료

 

3.3) 클래스

  • sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300. tol=0.0001,precomput_distance='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1, algorithm='auto')
  • n_clusters: 클러스터 개수
  • init 은 군집 중심점의 좌표를 설정하는 방법
  • max_iter : 최대 반복횟수
  • 훈련은 fit 이나 fit_transform 함수를 호출
  • labels_ 속성에 군집 중심점 레이블을 저장
  • cluster_centers_ 속성에 각 군집 중심점 좌표를 소유

 

3.4) 임의로 만든 데이터를 가지고 군집 분석 수행 - KMeans 이용

 

# 임의 데이터 생성과 시각화
from sklearn.datasets import make_blobs

blob_centers = np.array(
    [[ 0.2,  2.3],
     [-1.5 ,  2.3],
     [-2.8,  1.8],
     [-2.8,  2.8],
     [-2.8,  1.3]])
blob_std = np.array([0.4, 0.3, 0.1, 0.1, 0.1])

X, y = make_blobs(n_samples=2000, centers=blob_centers,
                  cluster_std=blob_std, random_state=7)
def plot_clusters(X, y=None):
    plt.scatter(X[:, 0], X[:, 1], c=y, s=1)
    plt.xlabel("$x_1$", fontsize=14)
    plt.ylabel("$x_2$", fontsize=14, rotation=0)
    
plt.figure(figsize=(8, 4))
plot_clusters(X)
save_fig("blobs_plot")
plt.show()

#결정 경계 확인 - veronoi diagram(평면을 특정 점까지의 거리가 가까운 점의 집합으로 )
def plot_data(X):
    plt.plot(X[:, 0], X[:, 1], 'k.', markersize=2)

def plot_centroids(centroids, weights=None, circle_color='w', cross_color='k'):
    if weights is not None:
        centroids = centroids[weights > weights.max() / 10]
    plt.scatter(centroids[:, 0], centroids[:, 1],
                marker='o', s=35, linewidths=8,
                color=circle_color, zorder=10, alpha=0.9)
    plt.scatter(centroids[:, 0], centroids[:, 1],
                marker='x', s=2, linewidths=12, 
                color=cross_color, zorder=11, alpha=1)
                

def plot_decision_boundaries(clusterer, X, resolution=1000, show_centroids=True,
                             show_xlabels=True, show_ylabels=True):
    mins = X.min(axis=0) - 0.1
    maxs = X.max(axis=0) + 0.1
    xx, yy = np.meshgrid(np.linspace(mins[0], maxs[0], resolution),
                         np.linspace(mins[1], maxs[1], resolution))
    Z = clusterer.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)

    plt.contourf(Z, extent=(mins[0], maxs[0], mins[1], maxs[1]),
                cmap="Pastel2")
    plt.contour(Z, extent=(mins[0], maxs[0], mins[1], maxs[1]),
                linewidths=1, colors='k')
    plot_data(X)
    if show_centroids:
        plot_centroids(clusterer.cluster_centers_)

    if show_xlabels:
        plt.xlabel("$x_1$", fontsize=14)
    else:
        plt.tick_params(labelbottom=False)
    if show_ylabels:
        plt.ylabel("$x_2$", fontsize=14, rotation=0)
    else:
        plt.tick_params(labelleft=False)
#결정 경계 확인 함수 호출
plt.figure(figsize=(8, 4))
plot_decision_boundaries(kmeans, X)
save_fig("voronoi_plot")
plt.show()

 

3.5) k-means 의 문제점

  • 데이터를 클러스터에 할당할 때 거리만을 고려하기 때문에 클러스터의 크기가 많이 다르면 제대로 동작하지 않ㅇ르 수 있습니다.
클러스터의 크기가 유사할 때 잘 동작함
  • 샘플을 하나의 클러스터에 할당하는 방식을 하드 군집(Hard Clustering) 이라고 하고 클러스터 마다 샘플에 점수를 부여하는 방식은 소프트 군집(Soft Clustering) 이라고 하는데 이 점수는 샘플과 centroid 간의 거리가 될 수도 있고 유사도 점수 일 수도 있습니다.
  • K-Means 클래스의 trasform()을 이용하면 각 샘플과 centroid 사이의 거리를 반환
print(kmeans.transform(X_new))
print(kmeans.predict(X_new))

 

3.6) 복잡도

  • 샘플 개수와 클러스터 개수 그리고 차원 개수에 선형
  • 일반적으로 갖아 빠른 군집 알고리즘

 

3.7) Centroid 초기화

  • Centroid 위치를 근사하게 알고있다면 init 하이퍼 파라미터에 centroid 리스트를 담은 numpy의 ndarray를 이용해서 지정하고 n_init을 1로 설정
init 하이퍼 파라미터를 설정하지 않으면 랜덤하게 centroid를 설정하게 되는데, 처음 이 값이 잘못 설정되면 최적화를 하지 못할 수 있음.
  • n_init은 centroid를 옮기는 횟수
#centroid 초기화
kmeans_iter1 = KMeans(n_clusters=5, init="random", n_init=1,
                      algorithm="full", max_iter=1, random_state=0)
kmeans_iter2 = KMeans(n_clusters=5, init="random", n_init=1,
                      algorithm="full", max_iter=2, random_state=0)
kmeans_iter3 = KMeans(n_clusters=5, init="random", n_init=1,
                      algorithm="full", max_iter=3, random_state=0)
kmeans_iter1.fit(X)
kmeans_iter2.fit(X)
kmeans_iter3.fit(X)

#centroid 초기화 시각화        
plt.figure(figsize=(10, 8))

plt.subplot(321)
plot_data(X)
plot_centroids(kmeans_iter1.cluster_centers_, circle_color='r', cross_color='w')
plt.ylabel("$x_2$", fontsize=14, rotation=0)
plt.tick_params(labelbottom=False)
plt.title("Update the centroids (initially randomly)", fontsize=14)

plt.subplot(322)
plot_decision_boundaries(kmeans_iter1, X, show_xlabels=False, show_ylabels=False)
plt.title("Label the instances", fontsize=14)

plt.subplot(323)
plot_decision_boundaries(kmeans_iter1, X, show_centroids=False, show_xlabels=False)
plot_centroids(kmeans_iter2.cluster_centers_)

plt.subplot(324)
plot_decision_boundaries(kmeans_iter2, X, show_xlabels=False, show_ylabels=False)

 

3.8) 성능 평가 지표

  • 각 샘플과 가장 가까운 centroid 사이의 평균 제곱 거리 (inertia 라고 함)
  • inertia_ 라는 속성을 이용해서 확인이 가능하고 score()를 호출하면 inertia를 음수 값으로 반환
inertia는 거리의 개념이기 때문에 작은 숫자가 잘 만들어진 모델
  • sklearn은 높은 점수가 좋다라는 원칙을 가지고 있음
# 평가지표 출력
print(kmeans.inertia_)
print(kmeans.score(X))

## result
211.59853725816836
-211.59853725816836

 

 

3.9) K-Means++

  • K-Means는 랜덤하게 중심점을 초기화하는데 K-Means ++은 성능향상을 위해서 첫번째 중심점을 선택한 후 다음 중심점은 거리가 먼 중심점을 선택하는 방식
  • sklearn의 K-Means 클래스는 이 방식이 기본이며 랜덤한 초기화를 하고자 하는 경우에는 init 매개변수를 random으로 설정하면 됩니다.

 

3.10) 속도 개선

  • 불필요한 계산을 줄이기 위해서 삼각 부등식을 사용 : centroid 사이의 거리를 위한 하한선과 상한선을 유지 - 기본적으로 이 방식을 사용하고 있으며 algorithm 매개변수를 full로 설정하면 이전 방식을 사용
  • 기본 K-Means 는 전체 데이터 세트를 가지고 centroid를 수정하는 방식을 사용하는데 반에 Mini Batch는 일부의 데이터만 가지고 centroid를 수정하도록 해서 속도를 3~4 배 정도 향상 시킴
미니 배치를 사용하고자 하는 경우에는 MiniBatchKMeans 클래스를 활용
%%time
k = 5
kmeans = KMeans(n_clusters=k, random_state = 42)
y_pred = kmeans.fit_predict(X)


%%time
from sklearn.cluster import MiniBatchKMeans
k = 5
miniBatchKMeans = MiniBatchKMeans(n_clusters=k, random_state=42)
y_pred = miniBatchKMeans.fit_predict(X)
print(miniBatchKMeans.inertia_)

## result 
#미니배치 미 사용
CPU times: total: 1.67 s
Wall time: 527 ms

#미니배치 사용
211.652398504332
CPU times: total: 1.16 s
Wall time: 406 ms

 

3.11) 클러스터 개수 설정

  • 최적의 클러스터 개수를 설정하는 방법은 2가지를 확인해서 수행
  • inertia 의 elbow를 찾아서 설정(inertia 값이 급격하게 변하는 지점)를 찾아서 설정
  • 실루엣 계수를 이용하는 방식 - 권장
#이너셔를 이용한 최적의 클러스터 개수 찾기
kmeans_per_k = [KMeans(n_clusters=k, random_state=42).fit(X)
                for k in range(1, 10)]
inertias = [model.inertia_ for model in kmeans_per_k]

plt.figure(figsize=(8, 3.5))
plt.plot(range(1, 10), inertias, "bo-")
plt.xlabel("$k$", fontsize=14)
plt.ylabel("Inertia", fontsize=14)
plt.annotate('Elbow',
             xy=(4, inertias[3]),
             xytext=(0.55, 0.55),
             textcoords='figure fraction',
             fontsize=16,
             arrowprops=dict(facecolor='black', shrink=0.1)
            )
plt.axis([1, 8.5, 0, 1300])
save_fig("inertia_vs_k_plot")
plt.show()

plot_decision_boundaries(kmeans_per_k[4-1], X)
plt.show()

  • 실루엣 계수를 이용하는 방식 - 이 방법을 권장
샘플의 실루엣 계수는 (b-a)/max(a, b) 로 구하는데 a 는 동일한 클러스터에 있는 다른 데이터 와의 평균 거리이고 b 는 가장 가까운 클러스터까지의 평균 거리
실루엣 계수는 -1 ~ + 1 까지
+1 에 가까워지면 자신의 클러스터 안에 잘 속해 있고 다른 클러스터 와는 멀리 떨어져 있음
실루엣 계수가 0에 가까워지면 경계에 위치한다는 의미이고 -1에 가까우면 샘플이 클러스터에 잘 못 할당된 것
  • sklearn.metrics.silhouette_samples(X, labels, metric= ’euclidean ’ **kwds):
인자로 X feature 데이터 세트와 각 피처 데이터 세트가 속한 군집 레이블 값인 labels 데이터를 입력해주면 각 데이터 포인트의 실루엣 계수를 계산해 반환
  • sklearn.metrics.silhouette_score(X, labels, metric= ’euclidean ’, sample_size=None, **kwds):
인자로 X feature 데이터 세트와 각 피처 데이터 세트가 속한 군집 레이블 값인 labels 데이터를 입력해주면 전체 데이터의 실루엣 계수 값을 평균해 반환
#실루엣 점수 출력
from sklearn.metrics import silhouette_score

silhouette_score(X, kmeans.labels_)

## 결과
0.655517642572828
silhouette_scores = [silhouette_score(X, model.labels_)
                     for model in kmeans_per_k[1:]]

plt.figure(figsize=(8, 3))
plt.plot(range(2, 10), silhouette_scores, "bo-")
plt.xlabel("$k$", fontsize=14)
plt.ylabel("Silhouette score", fontsize=14)
plt.axis([1.8, 8.5, 0.55, 0.7])
save_fig("silhouette_score_vs_k_plot")
plt.show()

 

 

 

3.12) K-Means 의 한계

  • 속성의 개수가 많으면 정확도가 떨어짐
  • 클러스터의 크기나 밀집도가 원형이 아니면 잘 작동하지 않음
from sklearn.datasets import make_moons
X, y = make_moons(200, noise=.05, random_state=42)
plt.scatter(X[:, 0], X[:, 1], s=50, cmap='viridis');

labels = KMeans(2, random_state=0).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');

 

3.13) 군집을 이용한 이미지 분할

  • 이미지를 세그먼트 여러 개로 분할할 때 사용이 가능
  • 복잡한 이미지의 경우는 Deep Learning의 CNN 을 많이 이용하는데 구별해야 할 이미지나 색상이 단순한 경우에는 KMeans 로도 충분함.
#군집을 이용한 이미지 분할

#이미지를 읽어와서 출력하기 
from matplotlib.image import imread
image = imread('./ladybug.jpg')
print(image.shape)

plt.figure(figsize=(10,5))
plt.subplots_adjust(wspace=0.05, hspace=0.1)

plt.subplot(231)
plt.imshow(image)
plt.title("Original image")
plt.axis('off')

#색상을 가지고 군집을 수행
X = image.reshape(-1, 3)
kmeans = KMeans(n_clusters=8, random_state=42).fit(X)
#각 픽셀이 속한 클러스터의 중앙 좌표를 저장
segmented_img = kmeans.cluster_centers_[kmeans.labels_]
segmented_img = segmented_img.reshape(image.shape)
segmented_imgs = []
n_colors = (10, 8, 6, 4, 2)
for n_clusters in n_colors:
    kmeans = KMeans(n_clusters=n_clusters, random_state=42).fit(X)
    segmented_img = kmeans.cluster_centers_[kmeans.labels_]
    segmented_imgs.append(segmented_img.reshape(image.shape))
    
for idx, n_clusters in enumerate(n_colors):
    plt.subplot(232 + idx)
    plt.imshow(segmented_imgs[idx].astype('uint8'))
    plt.title("{} colors".format(n_clusters))
    plt.axis('off')

save_fig('image_segmentation_diagram', tight_layout=False)
plt.show()

  • 흑백 이미지의 경우는 0 ~ 255 사이의 숫자로 하나의 픽셀을 나타내는데 대비를 명확하게 하고자 할 때는 threshold를 설정하고 0과 1로 수정해서 사용

3.14) 군집을 이용한 준 지도 학습

  • 군집을 수행한 후 분류 모델을 학습하면 조금 더 나은 성능을 발휘하는 경우가 있음.
  • 차원 축소하는 개념을 이용
#군집을 이용한 차원 축소 후 분류
#8*8 크기의 흑백 숫자 이미지 1797개 가져오기

from sklearn.datasets import load_digits

X_digits, y_digits = load_digits(return_X_y=True)

print(X_digits.shape)
print(y_digits.shape)

## result
(1797, 64)
(1797,)
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X_digits, y_digits, random_state=42)

#로지스틱 회귀 수행
from sklearn.linear_model import LogisticRegression

log_reg = LogisticRegression(multi_class="ovr", solver="lbfgs", max_iter=5000, random_state=42)
log_reg.fit(X_train, y_train)

log_reg_score = log_reg.score(X_test, y_test)
log_reg_score


## result
0.9688888888888889

 

#차원 축소

#k-Means 를 이용한 전처리 후 로지스틱 회귀 수행
from sklearn.pipeline import Pipeline

pipeline = Pipeline([
    ("kmeans", KMeans(n_clusters=50, random_state=42)),
    ("log_reg", LogisticRegression(multi_class="ovr", solver="lbfgs", max_iter=5000, random_state=42)),
])
pipeline.fit(X_train, y_train)

pipeline_score = pipeline.score(X_test, y_test)
pipeline_score

## result
0.9777777777777777 !
#오차율 확인
1 - (1 - pipeline_score) / (1 - log_reg_score)

## result 
0.28571428571428414
%%time
#최적의 클러스터 개수 찾기
from sklearn.model_selection import GridSearchCV

param_grid = dict(kmeans__n_clusters=range(2, 100))
grid_clf = GridSearchCV(pipeline, param_grid, cv=3, verbose=2)
grid_clf.fit(X_train, y_train)
print(grid_cif.best_params_)
print(gird_cif.score(X_test, y_test))

 


4. 계층적 클러스터링

4.1) 개요

  • 계층적인 트리로 클러스터를 조직화하는 방법
  • 특이점 또는 비정상적인 그룹이나 레코드를 발견하는데 민감
  • 직관적인 시각화가 가능하기 때문에 클러스터를 해석하기가 용이

4.2) 용어

  • Dendrogram : 계층적 클러스터를 시각화 한것
  • Distance : 한 레코드가 다른 레코드와 얼마나 가까운지를 보여주는 지표
  • Dissimilarity(비유사도) : 한 클러스터가 다른 클러스터들과 얼마나 가까운지를 보여주는 지표

4.3) 사용하는 경우

  • 컴퓨터 자원을 많이 소모하기 때문에 수만 개 정도의 레코드까지만 사용

4.4) 방법

  • 분할 계층 군집 : 전체 데이터를 하나의 클러스터에 할당하고 더 작은 클러스터로 반복적으로 나누는 방식
  • 병합 계층 군집 : 하나의 데이터를 하나의 클러스터로 만들고 가장 가까운 클러스터를 병합해나가는 방식
구현을 할 때는 가장 비슷한 샘플의 거리를 계산해서 병합할 수 도 있고 가장 먼 거리의 샘플을 이용해서 병합하기도 합니다.
평균 연결과 중심 연결 그리고 와드 연결(군집 내 편차들의 제곱합) 3가지 알고리즘을 이용
#병합군집
#샘플 데이터 생성
np.random.seed(42)
variables = ['X', 'Y', 'Z']
labels = ['ID_0','ID_1','ID_2', 'ID_3', 'ID_4']
X = np.random.random_sample([5,3])*10

df = pd.DataFrame(X, columns=variables, index=labels)

print(df)

##result 
             X         Y         Z
ID_0  3.745401  9.507143  7.319939
ID_1  5.986585  1.560186  1.559945
ID_2  0.580836  8.661761  6.011150
ID_3  7.080726  0.205845  9.699099
ID_4  8.324426  2.123391  1.818250
#거리 계산 - 유클리디안 거리
from scipy.spatial.distance import pdist, squareform
row_dist = pd.DataFrame(squareform(pdist(df, metric='euclidean')),
    columns=labels, 
    index=labels)
print(row_dist)

## result

           ID_0       ID_1       ID_2       ID_3       ID_4
ID_0   0.000000  10.067500   3.527332  10.163608  10.283767
ID_1  10.067500   0.000000   9.973350   8.323293   2.418558
ID_2   3.527332   9.973350   0.000000  11.285037  10.967857
ID_3  10.163608   8.323293  11.285037   0.000000   8.205581
ID_4  10.283767   2.418558  10.967857   8.205581   0.000000

 

#계층적 클러스터링 수행
from scipy.cluster.hierarchy import linkage
row_clusters = linkage(row_dist, method='complete')
pd.DataFrame(row_clusters,
             columns=['row label 1', 'row label 2','distance','no. of items in clust.'],
             index=['cluster %d' %(i+1) for i in range(row_clusters.shape[0])])

#첫번째와 두번째는 병합된 클러스터 이름이고 세번째는 거리, 네번째는 아이템 개수
#처음에는 클러스터가 데이터 개수만큼 -> 5개
#가까운 것끼리 합쳐지면서 1-4 / 0-2/ 3-5/ 6-7 합쳐지면서 데이터 5개 
##result
	row label 1	row label 2	distance	no. of items in clust.
cluster 1	1.0	4.0	3.570507	2.0
cluster 2	0.0	2.0	5.159321	2.0
cluster 3	3.0	5.0	13.182329	3.0
cluster 4	6.0	7.0	18.782841	5.0

 

#덴드로그램 출력
#계층적 군집을 시각화하는 도구
from scipy.cluster.hierarchy import dendrogram

# 검은색 덴드로그램 만들기
# from scipy.cluster.hierarchy import set_link_color_palette
# set_link_color_palette(['black']
row_dendr = dendrogram(row_clusters,labels=labels)

plt.tight_layout() 
plt.ylabel('유클리디안 거리') 
plt.show()

#히트맵에 덴드로그램 연결
#새로운 figure 객체를 만들고 add_axes 함수를 사용해서 덴드로그램의 x축 위치, y축 위치, 너비, 높이를 지정
#덴드로그램을 반시계 방향으로 90도 회전
fig = plt.figure(figsize=(8,8), facecolor='white')
axd = fig.add_axes([0.09,0.1,0.2,0.6])
row_dendr = dendrogram(row_clusters, orientation='left')

#파이썬 딕셔너리인 덴드로그램 객체의 leaves 키에서 얻은 클러스터 레이블을 따라 원 본 DataFrame에 있는 데이터를 재정렬
df_rowclust = df.iloc[row_dendr['leaves'][::-1]]

#재정렬된 DataFrame에서 히트맵을 만들고 덴드로그램 다음에 위치
axm = fig.add_axes([0.23,0.1,0.6,0.6])
cax = axm.matshow(df_rowclust, 
                  interpolation='nearest', 
                  cmap='hot_r')
# 축 눈금을 제거하고 그래프 테두리를 숨김
# 컬러 막대를 추가하고 특성과 샘플 이름을 각각 x축과 y축 눈금의 레이블로 할당
axd.set_xticks([])
axd.set_yticks([])
for i in axd.spines.values():
    i.set_visible(False)

fig.colorbar(cax)
axm.set_xticklabels([''] + list(df_rowclust.columns))
axm.set_yticklabels([''] + list(df_rowclust.index))
plt.show()

from sklearn.cluster import AgglomerativeClustering
ac = AgglomerativeClustering(n_clusters=3,
                              affinity='euclidean',
                              linkage='complete')
labels = ac.fit_predict(X)
print('클러스터 레이블: %s' % labels)

## result

클러스터 레이블: [0 1 0 2 1]
#계층적 클러스터링 수행
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
from scipy.stats import multivariate_normal

syms1 = ['AAPL', 'AMZN', 'AXP', 'COP', 'COST', 'CSCO', 'CVX', 'GOOGL', 'HD', 
         'INTC', 'JPM', 'MSFT', 'SLB', 'TGT', 'USB', 'WFC', 'WMT', 'XOM']
df = sp500_px.loc[sp500_px.index >= '2011-01-01', syms1].transpose()

Z = linkage(df, method='complete')
print(Z.shape)

##result

5. GMM(가우시안 혼합 모델)

 

5.1) 개요

  • 샘플이 파라미터가 알려지지 않은 여러 개의 혼합된 Gaussian 분포(정규 분포)에서 생성되었다고 가정하는 확률 모델
  • 정규 분포 : 평균이 0이고 표준 편차가 1인 정규분포
표준 편차의 1배 내의 68.27%
표준 편차의 2배 내에 95.45%
표준 편차의 3배 내에 99.73%

 

5.2) 클래스

  • sklearn.mixture의 GaussianMixture
  • 가장 중요한 하이퍼파라미터는 n_comonents로 몇 개의 군집을 생성할 것인지 여부를 설정
  • 생성 모델이라서 sample 함수를 이용해서 새로운 데이터 생성 가능
#샘플 데이터를 3개의 군집으로 묶기

X1, y1 = make_blobs(n_samples=1000, centers=((4, -4), (0, 0)), random_state=42)
X1 = X1.dot(np.array([[0.374, 0.95], [0.732, 0.598]]))
X2, y2 = make_blobs(n_samples=250, centers=1, random_state=42)
X2 = X2 + [6, -8]
X = np.r_[X1, X2]
y = np.r_[y1, y2]

from sklearn.mixture import GaussianMixture

gm = GaussianMixture(n_components=3, n_init=10, random_state=42)
gm.fit(X)
print(gm.weights_) #가중치 확인
print(gm.means_) #중심점 좌표
print(gm.covariances_) #공분산
print(gm.converged_)
print(gm.n_iter_) #횟수
print(gm.predict(X)) #예측
print(gm.predict_proba(X)) #확률
#생성 모델이라서 sample 함수를 이용해서 새로운 데이터 생성 가능
X_new, y_new = gm.sample(6)
X_new

#모델의 밀도 확인
gm.score_samples(X)

 

 

 

 

반응형
LIST

'LG 헬로비전 DX DATA SCHOOL > Python' 카테고리의 다른 글

차원 축소 (DimensionalityReduction)  (0) 2023.09.04
군집 분석 2  (0) 2023.09.04
회귀분석  (0) 2023.08.30
Pandas 의 연산  (0) 2023.08.16
Python 탐색적 시각화  (2) 2023.08.11