1. 程式人生 > >聚類實踐(無監督學習)

聚類實踐(無監督學習)

TensorFlow 聚類相關實現學習

注:聚類這一相關的無監督學習涉及到了很多的演算法,及其原理,如:Kmeans、Kmeans++、層次聚類、基於密度的聚類、以及譜聚類等等。這裡主要通過使用 TensorFlow 實現 Kmeans 以及 Knn 演算法(這裡採用半監督學習方法實現,以達到學習 TensorFlow API 的目的。其他具體演算法的講解,請參看別處。

一、從資料中學習 === > 無監督學習

1.1 概念簡介

  • 無監督學習可以從給定的資料集中找到感興趣的模式(pattern),它一般不給出標籤或者模式的資訊,需要自動探索資訊是怎麼組成的,並識別資料中的不同結構。
  • 聚類是指標對沒有標籤(unlabeled)的資料,尋找具有相同特徵的資料,並將其分配到形同的組或者簇。其中,為了將不同的成員分配到形同的簇中,於是對於表示不同元素之間的距離(distance)就顯的比較重要了,事實也是如此,有針對各種不同情況的距離的定義。

1.2 演算法實現流程

1.2.1 K 均值演算法

  1. 初始化,隨機以 K 個元素作為起始質心。為了簡化,可以採用元素列表的前 K 個元素作為質心。你也可以採用你自己風格的初始化
  2. 計算每個樣本跟質心的距離,並將樣本分配給距離它最近的質心所屬的簇,重新計算分配之後的質心。相當於質心不斷移動迭代。
  3. 在質心更新之後,它們的位移將引起質心和其他樣本的距離發生改變,故需要重新分配樣本所屬於的簇
  4. 在停止條件滿足之前,不斷重複第二步和第三步。

對於停止條件我們可以有不同的選擇:如下

  • 選擇一個比較大的迭代次數,它可能帶來冗餘的計算。
  • 當所有的樣本都已經穩定,即沒有元素從一個類轉移到另一個類時,就意味著迭代結束。

1.2.2 Knn(K 近鄰,這裡採用半監督學習方式實現)

  1. 設定訓練集的資料類別資訊
  2. 讀取下一個要分類的樣本,並計算新樣本到訓練集的每個樣本的歐幾里得距離。
  3. 根據歐幾里得距離最近的樣本來確定新樣本的類別資訊。
  4. 重複以上步驟,直到所有測試樣本都確定了類別停止。

二、演算法實現

2.1 Kmeans 演算法實現

# coding: utf-8
import tensorflow as tf import numpy as np import time import matplotlib as mpl import matplotlib.pyplot as plt from sklearn.datasets.samples_generator import make_blobs from sklearn.datasets.samples_generator import make_circles def bucket_mean(data,bucker_ids,num_buckers): # 各自按照不同的類別(即bucker_ids)進行相加,且bucker_ids 不保證順序 total = tf.unsorted_segment_sum(data,bucker_ids,num_buckers) count = tf.unsorted_segment_sum(tf.ones_like(data),bucker_ids,num_buckers) return total / count if __name__ == '__main__': # 首先第一步就是構造資料 DATA_TYPE = 'blobs' N = 200 # 首先確定聚類的 K 值,即聚類個數 # Number of clusters, if we choose circles, only 2 will be enough if (DATA_TYPE == 'circle'): K = 2 else: K = 4 # 開始計時 start = time.time() # 迭代次數 MAX_ITERS = 1000 # 聚類中心 centers = [(-2,-2),(-2,1.5),(1.5,-2),(2,1.5)] if (DATA_TYPE == 'circle'): # make_circles 函式建立兩個一大一下的圓環(由200個點構成),noise 是高斯噪聲,factor 是內外圓之間的放大因子 data, features = make_circles(n_samples=200,shuffle=True,noise=0.01,factor=0.4) else: # 注意這裡構造的是同方差 cluster_std 為一個值 data, features = make_blobs(n_samples=200,centers=centers,n_features=2,cluster_std=0.8,shuffle=False,random_state=42) # print type(data), data.shape, '\n' # print features fig, ax = plt.subplots() plt.figure(figsize=(10,8),facecolor='w') if DATA_TYPE == 'blobs': # plt.subplot(1,2,1) ax.scatter(np.asarray(centers).T[0],np.asarray(centers).T[1],marker = 'o',s=250) # 當需要將四組不同的類別的樣本著上不同的顏色時,便需要將 c = features 有多少類別傳入作為依據 # plt.subplot(1,2,2) ax.scatter(data.T[0],data.T[1],marker='*',s=100,c=features,cmap=plt.cm.coolwarm) # plt.show() # 接著,第二步便是給初值,計算樣本與質心的距離,更新質心,迭代 points = tf.Variable(data) # point 用來存放資料集點的集合 # 用來儲存樣本被聚到哪一類,初始置為 0 cluster_assignments = tf.Variable(tf.zeros([N],dtype=tf.int64)) # centroids 用於儲存質心座標,初始化為任意k個點,這裡取data 的前K個 centroids = tf.Variable(tf.slice(points.initialized_value(),[0,0],[K,2])) # 開啟 TensorFlow 會話 sess = tf.Session() sess.run(tf.global_variables_initializer()) sess.run(centroids) # 第三步,便是定義損失函式以及優化,及停止條件等 # print centroids,'\n' # print tf.tile(centroids,[2,1]) # 將質心做 N 次複製,對每個樣本做 K 次複製,這樣樣本的和質心形狀都是 N*K*2 ,即 N個樣本,K個簇 # 於是,我們便可以計算每個樣本到每個質心點之間的所有維度的距離 rep_centroids = tf.reshape(tf.tile(centroids,[N,1]),[N,K,2]) # print rep_centroids rep_points = tf.reshape(tf.tile(points,[1,K]),[N,K,2]) # print tf.square(rep_points - rep_centroids) sum_squares = tf.reduce_sum(tf.square(rep_points - rep_centroids), reduction_indices=2) # print sum_squares # 尋找距離最小的中心,返回其最小距離的序號,即哪一個簇 best_centroids = tf.argmin(sum_squares,1) # 這裡採用當所有質心不再發生變化作為停止條件,以下為是否更新質心得 flag did_assignments_change = tf.reduce_any(tf.not_equal(best_centroids,cluster_assignments)) # bucket_mean 函式用來更新新的質心 means = bucket_mean(points,best_centroids,K) # 然後,根據 control_dependencies 來判別是否更新質心, # 可以用tf.control_dependencies(control_inputs)來實現指定某些操作執行的依賴關係, # 它會返回一個控制依賴的上下文管理器,使用with關鍵字可以讓在這個上下文環境中 # 的操作都在 control_inputs 執行 with tf.control_dependencies([did_assignments_change]): # assign 賦值的意思 do_updates = tf.group(centroids.assign(means),cluster_assignments.assign(best_centroids)) changed = True iters = 0 fig, ax = plt.subplots() if DATA_TYPE == 'blobs': colourindexes = [2,1,4,3] else: colourindexes = [2,1] while changed and iters < MAX_ITERS: fig, ax = plt.subplots() iters += 1 [chagned, _] = sess.run([did_assignments_change,do_updates]) [centers,assignments] = sess.run([centroids,cluster_assignments]) ax.scatter(sess.run(points).T[0],sess.run(points).T[1],marker='o',s=200,c=assignments,cmap=plt.cm.coolwarm) # ax.scatter(np.asarray(centers).T[0],np.asarray(centers).T[1], marker = '^', s = 550, c = colourindexes, cmap=plt.cm.plasma) ax.scatter(centers[:,0],centers[:,1],marker='^',s=550,c=colourindexes,cmap=plt.cm.plasma) ax.set_title('Iteration' + str(iters)) plt.savefig('./My_pratise/Kmean_pic/kmeans' + str(iters) + '.png') ax.scatter(sess.run(points).T[0],sess.run(points).T[1],marker = 'o',s = 200,c=assignments,cmap=plt.cm.coolwarm) # plt.show() end = time.time() print 'Found in %.2f seconds'% (end - start), iters,'iterations' print 'Centroids:' print centers print 'Cluster assignments:',assignments

2.2 Knn 演算法實現

# coding:utf-8
import tensorflow as tf 
import numpy as np 
import time 

import matplotlib as mpl 
import matplotlib.pyplot as plt 
from sklearn.cross_validation import train_test_split
from sklearn.datasets.samples_generator import make_circles 
from sklearn.metrics import accuracy_score

if __name__ == '__main__':
    # 樣本點個數
    N = 210
    # 類別個數
    K = 2
    # 最大迭代次數
    MAX_ITERS = 1000
    # cut = int(N * 0.7)
    start = time.time()

    # 生成資料,劃分資料
    # noise 的取值較大,kmeans不擅長的非線性,的圓形資料集,這裡使用 knn
    data, features = make_circles(n_samples=N,shuffle=True,noise=0.12,factor=.4)
    data_train, data_test, features_train, features_test = train_test_split(data,features,test_size=0.3,random_state=1)

    fig, ax = plt.subplots()
    ax.scatter(data_train[:,0],data_train[:,1],marker='o',s=100, c=features_train,cmap=plt.cm.coolwarm)
    plt.plot()
    plt.grid(True)
    # plt.show()

    # point 用來存放資料集點的集合
    points = tf.Variable(data)
    # 用來儲存樣本被聚到哪一類,初始置為 0 
    cluster_assignments = tf.Variable(tf.zeros([N],dtype=tf.int64))

    # 建立會話
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())

    test = []

    for i, j in zip(data_test,features_test):
        distances = tf.reduce_sum(tf.square(tf.subtract(i, data_train)),reduction_indices=1)
        neighbor = tf.arg_min(distances,0)
        # 下面語句可以粗略觀察一下
        # print 'neighbor: ',features_train[sess.run(neighbor)]
        # print  'Real_value: ',j 
        test.append(features_train[sess.run(neighbor)])
    print test 
    # 可以通過此語句檢視 knn 的正確率

    fig, ax = plt.subplots()
    ax.scatter(data_test[:,0],data_test[:,1],marker='o',s=100,c=test,cmap=plt.cm.coolwarm)
    plt.plot()

    # final
    end = time.time()
    print ("Found in %.2f seconds" % (end-start))
    print 'clusster assignment:', test 
    print '準確率:',accuracy_score(features_test,test)

    plt.show()