Andrew Ng课程作业第七周(python版)

作业目的:学习无监督K-均值算法

作业内容:将多个平面散点划分为3个簇

提供的数据:ex7data2.txt(mooc可下载),X的第一、二列为横纵坐标

处理过程:

  • step1:读取数据
data=loadmat('d:/jupyter/ipython-notebooks-master/data/ex7data2.mat')
X=data['X']
X.shape
  • step2:在平面上随机取3个点作为簇的中心
def init_centroids(X,k):
     m,n=X.shape                 #300,2
     centroids=np.zeros((k,n))   #k=3
     idx=np.random.randit(0,m,k)       
     #从0到300随机选择3个数值
     for i in range(k):
          centroids[i,:]=X[idx[i],:]

     return centroids

init_centroids(X,3)
  • step3:根据初始中心找对应的所有簇中的点
def find_cluster(X,centroids):
    m=X.shape[0]
    k=centroids.shape[0]
    idx=np.zeros(m)

    for i in range(m):
        min_dist=100000
        for j in range(k):
             dist = np.sum((X[i,:] - centroids[j,:]) ** 2)
             if dist < min_dist:
                 min_dist = dist
                 idx[i] = j
     return idx

#idx为np数组,存储X每一个点所对应的簇中心(0,1,2)
  • step4:根据形成的三个簇重新计算中心节点
def compute_center(X,idx,k):
     m,n=X.shape
     centroids=np.zeros((k,n))    #初始化
    
     for i in range(k):
           indices = np.where(idx==i)                #每个簇对应的点在X中的位置
           #np.where在只有condition的情况下返回tuple of ndarrays,后面调用indices[0]
           sum_X=np.sum(X[indices,:],axis=1)   #求点每列的和
           centroids[i,:]=(sum_X/len(indices[0])).ravel()
           #取平均值,作为新的簇中心
  
      return centroids
compute_centroids(X,idx,3)
  • step5:综合上述步骤,将找簇和根据簇找新的中心的操作迭代进行
def run_k_means(X,initial_centroids,max_iters):
      m,n=X.shape
      k=initial_centroids.shape[0]
      idx=np.zeros(m)
      centroids = initial_centroids

      for i in range(max_iters):
            idx=find_cluster(X,centroids)
            centroids=compute_centroids(X,idx,k)

      return idx,centroids
  • step6:画图,确认分类结果
idx, centroids = run_k_means(X, initial_centroids, 10)
cluster1 = X[np.where(idx == 0)[0],:]
cluster2 = X[np.where(idx == 1)[0],:]
cluster3 = X[np.where(idx == 2)[0],:]

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(cluster1[:,0], cluster1[:,1], s=30, color='r', label='Cluster 1')
ax.scatter(cluster2[:,0], cluster2[:,1], s=30, color='g', label='Cluster 2')
ax.scatter(cluster3[:,0], cluster3[:,1], s=30, color='b', label='Cluster 3')
ax.legend()

p.s. 可能有人会问,为什么簇数量选择3,其实看X的分布图也能确定簇的数量为3,当然也可以用“肘部”观察法。

from sklearn.cluster import KMeans
from scipy.spatial.distance import cdist
K=range(1,5)
meandistortions=[]
for k in K:
    kmeans=KMeans(n_clusters=k)
    kmeans.fit(X)
    min_x=np.min(cdist(X,kmeans.cluster_centers_,'euclidean'),axis=1)
    meandistortions.append(sum(min_x)/X.shape[0])
plt.plot(K,meandistortions,'bx-')
plt.xlabel('k')
plt.ylabel('Average Dispersion')
plt.show()

因此,簇数量选择3。

p.s. 用scikit-learn库也可以。

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
kmeans_model=KMeans(n_clusters=3).fit(X)
print(kmeans_model.labels_)
cluster1 = X[np.where(kmeans_model.labels_== 0)[0],:]
cluster2 = X[np.where(kmeans_model.labels_ == 1)[0],:]
cluster3 = X[np.where(kmeans_model.labels_ == 2)[0],:]

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(cluster1[:,0], cluster1[:,1], s=30, color='r', label='Cluster 1')
ax.scatter(cluster2[:,0], cluster2[:,1], s=30, color='g', label='Cluster 2')
ax.scatter(cluster3[:,0], cluster3[:,1], s=30, color='b', label='Cluster 3')
ax.legend()
posted @ 2017-05-10 13:42  chaye_shui  阅读(70)  评论(0)    收藏  举报