聚類實踐(無監督學習)
阿新 • • 發佈:2018-12-29
TensorFlow 聚類相關實現學習
注:聚類這一相關的無監督學習涉及到了很多的演算法,及其原理,如:Kmeans、Kmeans++、層次聚類、基於密度的聚類、以及譜聚類等等。這裡主要通過使用 TensorFlow 實現 Kmeans 以及 Knn 演算法(這裡採用半監督學習方法實現,以達到學習 TensorFlow API 的目的。其他具體演算法的講解,請參看別處。
一、從資料中學習 === > 無監督學習
1.1 概念簡介
- 無監督學習可以從給定的資料集中找到感興趣的模式(pattern),它一般不給出標籤或者模式的資訊,需要自動探索資訊是怎麼組成的,並識別資料中的不同結構。
- 聚類是指標對沒有標籤(unlabeled)的資料,尋找具有相同特徵的資料,並將其分配到形同的組或者簇。其中,為了將不同的成員分配到形同的簇中,於是對於表示不同元素之間的距離(distance)就顯的比較重要了,事實也是如此,有針對各種不同情況的距離的定義。
1.2 演算法實現流程
1.2.1 K 均值演算法
- 初始化,隨機以 K 個元素作為起始質心。為了簡化,可以採用元素列表的前 K 個元素作為質心。你也可以採用你自己風格的初始化
- 計算每個樣本跟質心的距離,並將樣本分配給距離它最近的質心所屬的簇,重新計算分配之後的質心。相當於質心不斷移動迭代。
- 在質心更新之後,它們的位移將引起質心和其他樣本的距離發生改變,故需要重新分配樣本所屬於的簇
- 在停止條件滿足之前,不斷重複第二步和第三步。
對於停止條件我們可以有不同的選擇:如下
- 選擇一個比較大的迭代次數,它可能帶來冗餘的計算。
- 當所有的樣本都已經穩定,即沒有元素從一個類轉移到另一個類時,就意味著迭代結束。
1.2.2 Knn(K 近鄰,這裡採用半監督學習方式實現)
- 設定訓練集的資料類別資訊
- 讀取下一個要分類的樣本,並計算新樣本到訓練集的每個樣本的歐幾里得距離。
- 根據歐幾里得距離最近的樣本來確定新樣本的類別資訊。
- 重複以上步驟,直到所有測試樣本都確定了類別停止。
二、演算法實現
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()