聚类实践(无监督学习)

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()

猜你喜欢

转载自blog.csdn.net/smilejiasmile/article/details/80665584