機器學習做業---K-Means算法

--------------------------K-Means算法使用--------------------------

一:數據導入及可視化

import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio

data = sio.loadmat("ex7data2.mat")
X = data['X']  
print(X.shape)

plt.figure()
plt.scatter(X[:,0],X[:,1],c='b',marker="o")
plt.show()

注意:對於咱們的無監督學習中,訓練集中是沒有標籤值的,因此只有X,沒有y

二:歸類---尋找每一個訓練樣本的聚類中心

(一)代碼實現

def find_closest_centroids(X,centroids):
m = X.shape[0]
idx = np.zeros(m) #記錄每一個訓練樣本距離最短聚類中心最短的索引
idx = idx.astype(int) #由於numpy中沒有int、float類型,是由系統決定是3二、或者64位大小。因此咱們這裏手動設置位int類型,爲後面作準備

for i in range(m):
idx[i] = np.argmin(np.sum(np.power((centroids-X[i]),2),1)) #先計算各個中心到該點的平方和距離,返回最小的索引

return idx

(二)補充矩陣減去向量、np.sum的使用

(三)結果測試

k = 3  # 設置聚簇中心個數爲3
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]]) #手動初始化三個聚類中心點
idx = find_closest_centroids(X,initial_centroids)
print(idx[0:3])

三:根據上一步歸類結果---更新聚簇中心位置

 

(一)代碼實現

def compute_centroids(X,idx,K):
(m,n)=X.shape
centroids_new = np.zeros((k,n))

#進行更新操做,用每一個聚類中心全部點的位置平均值做爲新的聚類中心位置
for i in range(K):
centroids_new[i] = np.mean(X[np.where(idx==i)[0],0) #按列求均值

return centroids_new

(二)回顧np.where操做

 

注意:咱們這裏np.where返回的是一個元組類型,咱們若是想要獲取內部數據,應該使用np.where(idx == 5)[0]能夠獲取np.array類型數據

(三)結果測試

data = sio.loadmat("ex7data2.mat")
X = data['X']

k = 3  # 設置聚簇中心個數爲3
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]]) #手動初始化三個聚類中心點
idx = find_closest_centroids(X,initial_centroids)

c_n = compute_centroids(X,idx,k)
print(c_n)

四:實現K-mean算法

(一)代碼實現

def run_k_means(X,init_centroids,max_iters=0):
    m,n = X.shape
    idx = np.zeros(m)
    k = init_centroids.shape[0]
    centroids = init_centroids

    #開始迭代
    if max_iters != 0:
        for i in range(max_iters): #按迭代次數進行迭代
            idx = find_closest_centroids(X,centroids)
            centroids = compute_centroids(X,idx,k)
    else:
        while True: #直到連續兩次的迭代結果都是同樣的,就返回
            idx = find_closest_centroids(X, init_centroids)
            centroids = compute_centroids(X,idx,k)
            if (init_centroids == centroids).all():
                break
            init_centroids = centroids

    return idx,centroids

(二)結果顯示

data = sio.loadmat("ex7data2.mat")
X = data['X']

k = 3  # 設置聚簇中心個數爲3
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]]) #手動初始化三個聚類中心點

max_iters = 10
idx, centroids = run_k_means(X,initial_centroids,max_iters)
#獲取各個聚簇信息
cluster_1 = X[np.where(idx==0)[0],:]
cluster_2 = X[np.where(idx==1)[0],:]
cluster_3 = X[np.where(idx==2)[0],:]

#繪製圖像
plt.figure()
plt.scatter(cluster_1[:,0],cluster_1[:,1],c='r',marker="o")
plt.scatter(cluster_2[:,0],cluster_2[:,1],c='b',marker="o")
plt.scatter(cluster_3[:,0],cluster_3[:,1],c='g',marker="o")
plt.show()

(三)改進版---繪製聚簇中心移動軌跡

def run_k_means(X,init_centroids,max_iters=0):
    m,n = X.shape
    idx = np.zeros(m)
    k = init_centroids.shape[0]
    centroids = init_centroids
    cent_rec = init_centroids   #記錄中心移動信息

    #開始迭代
    if max_iters != 0:
        for i in range(max_iters):  #按迭代次數進行迭代
            idx = find_closest_centroids(X,centroids)
            centroids = compute_centroids(X,idx,k)
            cent_rec = np.append(cent_rec,centroids,axis=1)  #記錄中心移動信息,按列添加
    else:
        while True: #直到連續兩次的迭代結果都是同樣的,就返回
            idx = find_closest_centroids(X, init_centroids)
            centroids = compute_centroids(X,idx,k)
            if (init_centroids == centroids).all():
                break
            init_centroids = centroids
            cent_rec = np.append(cent_rec,centroids,axis=1)  #記錄中心移動信息,按列添加

    return idx,centroids,cent_rec
data = sio.loadmat("ex7data2.mat")
X = data['X']

k = 3  # 設置聚簇中心個數爲3
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]]) #手動初始化三個聚類中心點

max_iters = 10
idx, centroids, cent_rec = run_k_means(X,initial_centroids,max_iters)

#獲取各個聚簇信息
cluster_1 = X[np.where(idx==0)[0],:]
cent_1 = cent_rec[0].reshape(-1,2)
cluster_2 = X[np.where(idx==1)[0],:]
cent_2 = cent_rec[1].reshape(-1,2)
cluster_3 = X[np.where(idx==2)[0],:]
cent_3 = cent_rec[2].reshape(-1,2)


#繪製圖像
plt.figure()
plt.scatter(cluster_1[:,0],cluster_1[:,1],c='r',marker="o")
plt.plot(np.array(cent_1[:,0]),np.array(cent_1[:,1]),c='black',marker="X")
plt.scatter(cluster_2[:,0],cluster_2[:,1],c='b',marker="o")
plt.plot(np.array(cent_2[:,0]),np.array(cent_2[:,1]),c='black',marker="X")
plt.scatter(cluster_3[:,0],cluster_3[:,1],c='g',marker="o")
plt.plot(np.array(cent_3[:,0]),np.array(cent_3[:,1]),c='black',marker="X")
plt.show()

五:隨機初始化聚類中心函數

在運行 K-均值算法的以前,咱們首先要隨機初始化全部的聚類中心點。算法

(一)重點回顧

注意點一:

1)應該把聚類中心的數值K設置爲比訓練樣本數量m小的值;app

(2)隨機挑選K個訓練樣本;dom

(3)設定μ1,...,μk,讓它們等於這K個樣本。函數

注意點二:

避免局部最優:若是想讓找到最優可能的聚類,能夠嘗試屢次隨機初始化,以此來保證可以獲得一個足夠好的結果,選取代價最小的一個也就是代價函數J最小的。事實證實,在聚類數K較小的狀況下(2~10個),使用屢次隨機初始化會有較大的影響,而若是K很大的狀況,屢次隨機初始化可能並不會有太大效果。 

(二)代碼實現

def kmeans_init_centroids(X,k):  #隨機獲取聚類中心
    centroids = np.zeros((k,X.shape[1]))

    #隨機選取訓練樣本個數
    idx = np.random.choice(X.shape[0],k)
    centroids = X[idx,:]

    return centroids

def comp_J(X,centroids,idx):    #計算代價,計算平方和,不進行開方
    # 獲取各個聚簇信息
    cluster_1 = X[np.where(idx == 0)[0], :]
    cluster_2 = X[np.where(idx == 1)[0], :]
    cluster_3 = X[np.where(idx == 2)[0], :]

    #計算代價
    J_1 = np.sum(np.power(cluster_1-centroids[0],2))
    J_2 = np.sum(np.power(cluster_2-centroids[1],2))
    J_3 = np.sum(np.power(cluster_3-centroids[2],2))

    return J_1+J_2+J_3

def kmeans_run(X,k,rand_iter,max_iters=0):  #進行屢次計算代價,而後選取最小的
    min_J = -1
    idx_res = np.zeros(X.shape[0])
    centroids_res = np.zeros((k,X.shape[1]))
    cent_rec_res = centroids_res

    for i in range(rand_iter):
        init_centroids = kmeans_init_centroids(X,k)
        idx, centroids, cent_rec = run_k_means(X,init_centroids,max_iters)
        #計算代價
        if min_J < 0:
            min_J = comp_J(X,centroids,idx)
        else:
            new_J = comp_J(X,centroids,idx)
            # print(new_J)
            if new_J < min_J:
                idx_res, centroids_res, cent_rec_res = idx, centroids, cent_rec
    # print(min_J)
    return idx_res, centroids_res, cent_rec_res
data = sio.loadmat("ex7data2.mat")
X = data['X']

k = 3  # 設置聚簇中心個數爲3
rand_iter = 10

max_iters = 10
idx, centroids, cent_rec = kmeans_run(X,k,rand_iter,max_iters)

idx, centroids, cent_rec = run_k_means(X,kmeans_init_centroids(X,k),max_iters)
# print(comp_J(X,centroids,idx))  #266.65851965491936
#獲取各個聚簇信息
cluster_1 = X[np.where(idx==0)[0],:]
cent_1 = cent_rec[0].reshape(-1,2)
cluster_2 = X[np.where(idx==1)[0],:]
cent_2 = cent_rec[1].reshape(-1,2)
cluster_3 = X[np.where(idx==2)[0],:]
cent_3 = cent_rec[2].reshape(-1,2)


#繪製圖像
plt.figure()
plt.scatter(cluster_1[:,0],cluster_1[:,1],c='r',marker="o")
plt.plot(np.array(cent_1[:,0]),np.array(cent_1[:,1]),c='black',marker="X")
plt.scatter(cluster_2[:,0],cluster_2[:,1],c='b',marker="o")
plt.plot(np.array(cent_2[:,0]),np.array(cent_2[:,1]),c='black',marker="X")
plt.scatter(cluster_3[:,0],cluster_3[:,1],c='g',marker="o")
plt.plot(np.array(cent_3[:,0]),np.array(cent_3[:,1]),c='black',marker="X")
plt.show()

補充:咱們能夠認爲每一個點的特徵就是x_1,x_2,而咱們的聚類中心就是由x_1和x_2組成的。

--------------------------K-Means算法進行圖像壓縮--------------------------

使用K-Means進行圖像壓縮。咱們使用聚類來找到最具表明性的少數顏色,並使用聚類分配講原始的24位顏色,映射到較低維的顏色空間學習

一:數據讀取

image_data = sio.loadmat("bird_small.mat")
data = image_data['A']
print(data)
print(data.shape)

 

二:數據預處理

#數據歸一化  由於每一個數據都是0-255之間
data = data / 255
data = np.reshape(data,(data.shape[0]*data.shape[1],data.shape[2]))
print(data.shape)

注意:咱們的特徵就是顏色空間三通道,因此咱們後面求取的聚類中心就是咱們找到的最具表明的顏色空間 

三:獲取咱們的聚類中心(同以前)

(一)代碼實現

def find_closest_centroids(X,centroids):
    m = X.shape[0]
    idx = np.zeros(m)   #記錄每一個訓練樣本距離最短聚類中心最短的索引
    idx = idx.astype(int)   #由於numpy中沒有int、float類型,是由系統決定是3二、或者64位大小。因此咱們這裏手動設置位int類型,爲後面作準備

    for i in range(m):
        idx[i] = np.argmin(np.sum(np.power((centroids-X[i]),2),1))  #先計算各個中心到該點的平方和距離,返回最小的索引

    return idx

def compute_centroids(X,idx,K):
    (m,n)=X.shape
    centroids_new = np.zeros((k,n))

    #進行更新操做,用每一個聚類中心全部點的位置平均值做爲新的聚類中心位置
    for i in range(K):
        centroids_new[i] = np.mean(X[np.where(idx==i)[0]],0)    #按列求均值

    return centroids_new

def run_k_means(X,init_centroids,max_iters=0):
    m,n = X.shape
    idx = np.zeros(m)
    k = init_centroids.shape[0]
    centroids = init_centroids

    #開始迭代
    if max_iters != 0:
        for i in range(max_iters):  #按迭代次數進行迭代
            idx = find_closest_centroids(X,centroids)
            centroids = compute_centroids(X,idx,k)
    else:
        while True: #直到連續兩次的迭代結果都是同樣的,就返回
            idx = find_closest_centroids(X, init_centroids)
            centroids = compute_centroids(X,idx,k)
            if (init_centroids == centroids).all():
                break
            init_centroids = centroids

    return idx,centroids

def kmeans_init_centroids(X,k):
    centroids = np.zeros((k,X.shape[1]))

    #隨機選取訓練樣本個數
    idx = np.random.choice(X.shape[0],k)
    centroids = X[idx,:]

    return centroids

(二)獲取壓縮結果

image_data = sio.loadmat("bird_small.mat")
data = image_data['A']
#數據歸一化  由於每一個數據都是0-255之間
data = data / 255
X = np.reshape(data,(data.shape[0]*data.shape[1],data.shape[2]))
k = 16
max_iters = 10

#隨機初始化聚類中心
init_centroids = kmeans_init_centroids(X,k)
#獲取聚類中心
idx,centroids = run_k_means(X,init_centroids,max_iters)
#將全部數據點,設置歸屬到對應的聚類中心去 idx = find_closest_centroids(X,centroids) #將每個像素值與聚類結果進行匹配 X_recovered = centroids[idx,:] #將屬於一個聚類的像素,設置爲聚類中心的值(統一)

print(X_recovered.shape)    #(16384, 3)

X_recovered = np.reshape(X_recovered,(data.shape[0],data.shape[1],data.shape[2]))  #再展開爲三維數據

補充:使用索引擴展矩陣

(三)壓縮結果顯示

plt.figure()
plt.imshow(data)    #顯示原始圖像
plt.show()

plt.figure()
plt.imshow(X_recovered) #顯示壓縮後的圖像
plt.show()

當k=6時:測試

四:補充使用sklearn庫進行K-means算法使用

import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio
from sklearn.cluster import KMeans

image_data = sio.loadmat("bird_small.mat")
data = image_data['A']
#數據歸一化  由於每一個數據都是0-255之間
data = data / 255
X = np.reshape(data,(data.shape[0]*data.shape[1],data.shape[2]))

model = KMeans(n_clusters=16,n_init=100,n_jobs=-1) #n_init設置獲取初始簇中心的更迭次數,防止局部最優 n_jobs設置並行(使用CPU數,-1則使用全部CPU)
model.fit(X)    #開始聚類

centroids = model.cluster_centers_  #獲取聚簇中心
C = model.predict(X) #獲取每一個數據點的對應聚簇中心的索引

X_recovered = centroids[C].reshape((data.shape[0],data.shape[1],data.shape[2])) #獲取新的圖像

plt.figure()
plt.imshow(data)    #顯示原始圖像
plt.show()

plt.figure()
plt.imshow(X_recovered) #顯示壓縮後的圖像
plt.show()

參數講解:http://www.javashuo.com/article/p-wprucdjk-gu.html

相關文章
相關標籤/搜索