K-means
앞선 KNN은 라벨이 있는 상태에서 새로운 데이터의 위치를 찾는 분류 모델이었다.
K-means는 라벨이 없는 상태에서 데이터를 정해진 개수의 군집으로 나누는 비지도학습 알고리즘이다.
작동 방식은 다음과 같다.
코드 예시
import numpy as np
import cv2
import matplotlib.pyplot as plt
# load image
img = cv2.imread('MRI.png') # Reads an image into BGR Format
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #load image with RGB format
img_size = img.shape
print(img_size)
# Display original image
plt.imshow(img)
plt.title("Original Image")
plt.show()
# Reshape data
all_pixels = img.reshape((-1,3)).astype(float)
print(all_pixels.shape)
# Run k-means clustering
from sklearn.cluster import KMeans
K = 4 # Number of clusters
km_model = KMeans(n_clusters=K)
km_model.fit(all_pixels)
# Learned Centroids
centers = km_model.cluster_centers_
print(centers) # In RGB Format
# Display different cluster segments
segmented_img = km_model.labels_ # Clustering Result
segmented_img = segmented_img.reshape(img_size[0], img_size[1])
plt.imshow(segmented_img)
plt.title("k-Means Clustering")
plt.show()
# display different segments separately
for k in range(K):
plt.imshow(img*(segmented_img == k)[...,None])
plt.title('Cluster ' + str(k))
plt.show()
내가 작성한 코드
# L2 distance
def L2_distance(x, y):
return np.sqrt( np.sum((x - y)**2, axis=1) )
# My k-means implementation
def my_kMeans(all_data, num_clusters):
num_data, data_dim = all_data.shape # data size
# Centroid and cluster initialization
# centroids = np.random.rand(num_clusters, data_dim) * 256. # Random coordinate initialization
centroids = all_data[np.random.randint(num_data, size = num_clusters),:] # Random sample initialization
clusters = (-1)*np.ones(num_data) # initialize all the clusters with -1
max_iteration = 20
for iter in range(max_iteration):
# save current cluster
current_clusters = clusters.copy()
# update cluster
for k in range(num_data):
data = all_data[k] # each data
# For each data, find the distance from the centroids
dist = L2_distance(centroids, data)
# find minimum distance (index) & save
########### Implement your code here ######################
clusters[k] = np.argmin(dist) # dist 배열에 담긴 거리들 중 가장 작은 값(최단 거리)의 인덱스(클러스터 번호)를 저장합니다.
# update the centroids
for m in range(num_clusters):
cluster_map = (clusters == m)
num_samples_in_cluster = cluster_map.sum()
# find the average of the cluster samples
########### Implement your code here ######################
centroids[m] = np.mean(all_data[cluster_map], axis=0) # 할당된 데이터가 하나라도 있는 경우, 클러스터에 속한 데이터들의 축 0(axis=0)을 기준으로 평균(mean)을 구해 업데이트합니다.
# We stop when the clusters does not change
if np.sqrt(((current_clusters - clusters)**2).sum()) < 1e-20:
break
return clusters, centroids
# Run your kMeans
K = 4
labels, cent = my_kMeans(all_pixels, K)
# Display the segmentation results
seg_img = labels.reshape(img_size[0], img_size[1])
plt.imshow(seg_img)
plt.title("My k-Means Clustering")
plt.show()
for k in range(K):
plt.imshow(img*(seg_img == k)[...,None])
plt.title('Cluster ' + str(k))
plt.show()