๐์ด ํฌ์คํธ๋ K-means clustering ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
K-ํ๊ท ํด๋ฌ์คํฐ๋ง์ ์ฃผ์ด์ง ๋ฐ์ดํฐ๋ฅผ k๊ฐ์ ๊ตฐ์ง(= class = cluster)๋ก ๋ฌถ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋ปํฉ๋๋ค.
K-ํ๊ท ๊ตฐ์งํ๋ ์์คํจ์ ๊ฐ์ด ์ต์ํ๋ ๋๊น์ง ๊ตฐ์ง์ ์ค์ฌ(Centroid)๊ณผ ๊ฐ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ ๊ตฐ์ง์ ๋ฐ๋ณตํด์ ๊ณ์ฐํ๋ค.
์ด K-ํ๊ท ํด๋ฌ์คํฐ๋ง์
: ๊ตฐ์ง์ ๊ฐ์
: ๋ฒ์งธ ๊ตฐ์ง์ ์ํ๋ ๋ฐ์ดํฐ๋ค์ ์งํฉ
: ๋ฒ์งธ ๊ตฐ์ง์ ๋ฌด๊ฒ์ค์ฌ(centroid)
: ์ ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๋ปํ๋ค. ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ๋ ๋ฐฉ๋ฒ์ euclidean distance๋ฅผ ์ด์ฉํ๋ค.
์ ๋ iris dataset์ ์ด์ฉํ์ฌ K-ํ๊ท ํด๋ฌ์คํฐ๋ง์ ์ํํ์์ต๋๋ค.
โ ๏ธ๊ฐ ๋ผ์ธ๋ณ๋ก ์ฃผ์์ ๋ฌ์์ ๊ฐ ๋ผ์ธ์ด ๋ฌด์จ ์๋ฏธ์ธ์ง ์๋ ค๋๋ฆฌ๊ฒ ์ต๋๋ค.
def random_centroids(values, K): # K : ๊ตฐ์ง ๊ฐ์
centroids = []
# K๋ฒ ๋ฐ๋ณตํ์ฌ values ๋ฐ์ดํฐ์ค์ K๊ฐ๋ฅผ ๋ฌด๊ฒ์ค์ฌ์ผ๋ก ์ ์ธ
for i in range(K):
centroid = values[rand.randint(0, len(values)-1)]
centroids.append(centroid)
return centroids
์ด 3๊ฐ๋ฅผ ๋ฌถ์ด ๊ฐ ๋ฐ์ดํฐ๋ณ๋ก ๊ฐ์ฅ ๊ฐ๊น์ด ๊ตฐ์ง์ ์์์ํค๋ ํจ์๋ฅผ ์ ์ํ๋ค.
def assign_cluster(values, centroids):
assignments = [] #cluster assignments
# ๊ฐ ๋ฐ์ดํฐ๋ค
for value in values:
# ํ๋์ ๋ฐ์ดํฐ์ K๊ฐ์ ๋ฌด๊ฒ์ค์ฌ๊ณผ์ ๊ฑฐ๋ฆฌ๋ฅผ ์ ์ฅํ ๋ณ์
dist_point_clust = []
# ๊ฐ ๋ฌด๊ฒ์ค์ฌ๋ค
for centroid in centroids:
# ๋๋คํ ๋ฌด๊ฒ์ค์ฌ๊ณผ ๊ฐ ๋ฐ์ดํฐ ๊ฐ์ ์ธ๋ฑ์ค๋ณ๋ก ๋บ์
์ ์ํํ์ฌ ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ๋ค.
d_clust = np.linalg.norm(np.array(value) - np.array(centroid))
dist_point_clust.append(d_clust)
# ๊ฑฐ๋ฆฌ๊ฐ ์ต์์ธ ๊ฐ์ ์ธ๋ฑ์ค๋ฅผ ์ ์ฅ
assignment = np.argmin(dist_point_clust)
assignments.append(assignment)
return assignments
def new_centroids(values, centroids, assignments, K):
# values : ๋ฐ์ดํฐ
# centroids : ๋ฌด๊ฒ์ค์ฌ๋ค์ด ๋ชจ์ธ ๋ฆฌ์คํธ
# assignments : ๊ฐ ์ ๋ณ๋ก ์ด๋ ๊ตฐ์ง์ ์ํ๋์ง ์ ์ ์๋ ๋ฆฌ์คํธ
# K : ๊ตฐ์ง์ ๊ฐ์
# ์๋กญ๊ฒ ๊ณ์ฐ๋ ๋ฌด๊ฒ์ค์ฌ์ ์ถ๊ฐํ ๋ฆฌ์คํธ
new_centroids = []
for i in range(K):
# i_cluster :
i_cluster = []
for x in range(len(values)):
# x๋ฒ์งธ ๋ฐ์ดํฐ๊ฐ ์ํ ๊ตฐ์ง์ด i๋ฒ์งธ ๊ตฐ์ง๊ณผ ๊ฐ๋ค๋ฉด
if (assignments[x] == i):
# i_cluster์ ์ถ๊ฐ
i_cluster.append(values[x]) # append all single cluster points
# ๊ฐ ํด๋ฌ์คํฐ์ ์ํ๋ ๋ฐ์ดํฐ๋ค๋ผ๋ฆฌ ํ๊ท
mean_cluster = np.mean(i_cluster, axis=0) # mean value of the cluster points will serve as new centroid
# ๊ณ์ฐ๋ ํ๊ท ์ง์ ์ ์๋ก์ด ๋ฌด๊ฒ์ค์ฌ์ผ๋ก ์ค์
new_centroids.append(mean_cluster)
return new_centroids
def sse(values, assignments, centroids):
# values : ๋ฐ์ดํฐ
# assignments : ๊ฐ ์ ๋ณ๋ก ์ด๋ ๊ตฐ์ง์ ์ํ๋์ง ์ ์ ์๋ ๋ฆฌ์คํธ
# centroids : ๋ฌด๊ฒ์ค์ฌ๋ค์ด ๋ชจ์ธ ๋ฆฌ์คํธ
errors = []
for i in range(len(values)):
#get assigned centroid for each point
centroid = centroids[assignments[i]]
#compute the distance (error) between one point and its closest centroid
error = np.linalg.norm(np.array(values[i]) - np.array(centroid))
#append squared error to the list of error
errors.append(error**2)
#and sum up all the errors
sse = sum(errors)
return sse
์ด ๊ณผ์ ์ ๋ค ํฌ๊ดํ๋ ํจ์๋ฅผ ์ ์ํ๋ค. ๋์ค์ K-mean clustering์ ์ฐ๊ณ ์ถ์ ๋ ๋จ ํ ๋ฒ์ ํจ์ ํธ์ถ์ ํ๊ธฐ ์ํจ์ด๋ค.
def kmeans_clustering(values, K, max_iter = 100, tol = pow(10,-3) ):
# iteration : ๋ฐ๋ณต ํ์
it = -1
all_sse = []
assignments = []
# STEP 1. ์ด๊ธฐ ๋๋ค ๋ฌด๊ฒ์ค์ฌ ์์ฑ
centroids = random_centroids(values, K)
# ์๋ฌ๊ฐ 1 ์ดํ์ด๊ฑฐ๋ ์ต๋๋ฐ๋ณตํ์ ์๋์ ๋ฐ๋ณต์ค์ด๋ฉด์ { (ํ์ฌ ์์ค - ์ง์ ๊ณผ๊ฑฐ ์์ค) / ์ง์ ๊ณผ๊ฑฐ ์์ค } ์ด 0.001 ์ด์์ด๋ฉด ๋ฐ๋ณต ์งํ
while (len(all_sse)<=1 or (it < max_iter and np.absolute(all_sse[it] - all_sse[it-1])/all_sse[it-1] >= tol)):
it += 1
# STEP 2. ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ ๊ตฌํ๊ธฐ
assignments = assign_cluster(values, centroids)
#STEP 3. ๋ฌด๊ฒ์ค์ฌ ์ฌ์กฐ์
centroids = new_centroids(values, centroids, assignments, K)
#STEP 4. ์์ค๋ฅ ๊ตฌํ๊ธฐ
sse_kmeans = sse(values, assignments, centroids)
all_sse.append(sse_kmeans)
print('์๋ฌ์จ : {}'.format(sse_kmeans))
return (assignments, centroids, all_sse, it)
์ ์ฉ :
result = kmeans_clustering(values=values, K=4)
์๋ฌ์จ : 76.01591907424665
์๋ฌ์จ : 72.44054722344684
์๋ฌ์จ : 71.33622242453569
์๋ฌ์จ : 71.33622242453569
result ๋ณ์๋ 4์ฐจ์ ๋ณ์ ์ผ ๊ฒ์ด๋ค.
์๋ํ๋ฉด kmean_clustering ๋ฉ์๋๊ฐ 4๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ returnํ๊ธฐ ๋๋ฌธ์ ๊ธธ์ด๊ฐ 4์ผ ๊ฒ์ด๋ค.
์ด์ ์๊ฐํ๋ฅผ ํ์ฌ ๊ฐ ๋ฐ์ดํฐ๋ค์ด ์ด๋ ๊ตฐ์ง์ ์ํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
centroids_x = [result[1][x][0] for x in range(len(result[1]))] #sepal_length: [0]
centroids_y = [result[1][x][2] for x in range(len(result[1]))] #petal_length: [2]
x = data['sepal_length']
y = data['petal_length']
assignments = result[0] # result[0] = assignments
# reuslt[1] = centroids
# result[2] = all_sse
# result[3] = it
plt.scatter(x, y, c=assignments)
plt.plot(centroids_x,centroids_y, c='white', marker='.', linewidth='0.01', markerfacecolor='red', markersize=22)
plt.title("K-means Visualization")
plt.xlabel("sepal_length")
plt.ylabel("petal_length")
๋ณด์๋ ๋ฐ์ ๊ฐ์ด kmean_clustering() ๋ฉ์๋์ K=4 ๋ผ๊ณ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ๋ ฅํ์ฌ centroid(๋นจ๊ฐ์ ์ )์ด 4๊ฐ์ด๊ณ ๋ ธ๋์, ๋จ์, ๋ณด๋ผ์, ์ด๋ก์์ด ๊ฐ๊ฐ์ ๊ตฐ์ง์ ๋๋ค.
๐ป ๋ฐ๋ผ์ ํด๋น ๋ฐ์ดํฐ์ ๋ผ๋ฒจ์ ๋ชจ๋ฅด๋ ์ํ์์ ๋ถ๋ฅ๋ฅผ ํ์ฌ์ผ ํ ๋ ๋ฌด๊ฒ์ค์ฌ์ด๋ผ๋ ๊ฐ๋
์ ํตํด์ ๋ฌด๊ฒ์ค์ฌ๊ณผ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ์ฌ ํด๋์ค(๊ตฐ์ง)์ ๋ง๋ค์ด์ฃผ๋ ์ญํ ์ด ํ์ํฉ๋๋ค.
์ด๋ด ๋ K-means-clustering ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํ์ฌ ํด๋์ค๋ณ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฌถ์ด ์ค ์ ์์ต๋๋ค.