聚态算法及其Python实现学习笔记

简介

聚类即物以类聚,实现将数据按照某一标准(相似度)将整个数据集分为若干子集(簇),最终的分类结果要尽量保证组内相似度尽可能大,组间相似度尽可能小。
    聚类是典型的无监督学习(Unsupervised learning),它与分类问题最明显的区别就是分类问题有事先的标注,而聚类的分组是完全靠自己学习得来的。
    聚类可以作为一个单独的学习过程,为了寻找数据的内部分布结构,也可以作为其他任务的前驱过程。

相似度

相似度计算方法
  其中Minkowski距离是所有范式距离的统称,p=1时为曼哈顿距离,p=2时为欧式距离

其中Minkowski距离是所有范式距离的统称,p=1时为曼哈顿距离,p=2时为欧式距离

常见聚类方法

基于划分的聚类,如K-means
层次聚类,如Agglomerative clustering
密度聚类,DBSCAN
基于模型的聚类:高斯混合模型(GMM)
谱聚类(Spectral clustering)、AP聚类算法(Affinity propagation)等

聚类方法及其算法

K-means

简介

算法思想

基于划分的算法,想要的效果就是在需要聚类的散点数据集中划分出类内点足够近,类间点足够远。

算法流程

· 随机选择K个对象,每个对象表示一个簇的初始中心
· 对剩余的数据点,根据他到不同中心距离选择最短距离的中心点将其分类
· 分完后重新计算每个簇的均值,更新中心点
· 不断重复第二步和第三步,直到中心点位置变化不大为止。

算法优缺点

优点:
        · 简单高效
        · 时空复杂度都较低
缺点:
        · 需要预先设定K值且对一开始的随机点位置很敏感
        · 容易形成局部最优解
        · 对噪声和离群值很敏感
        · 不能解决非凸(non-convex)数据

算法流程

1 首先从n个数据对象任意选择 k 个对象作为初始聚类中心;


#随机选择K个点
k = rd.sample(range(count), k_count)
k_point = [[x[i], [y[i]]] for i in k]   #保证有序
k_point.sort()

2 根据每个聚类对象的均值(中心对象),计算每个对象与这些中心对象的距离;并根据最小距离重新对相应对象进行划分;

        km = [[] for i in range(k_count)]      #存储每个簇的索引
        #遍历所有点
        for i in range(count):
            cp = [x[i], y[i]]                   #当前点
            #计算cp点到所有质心的距离
            _sse = [distance(k_point[j], cp) for j in range(k_count)]
            #cp点到那个质心最近
            min_index = _sse.index(min(_sse))   
            #把cp点并入第i簇
            km[min_index].append(i)

3 重新计算每个(有变化)聚类的均值(中心对象);

        #更换质心
        step+=1
        k_new = []
        for i in range(k_count):
            _x = sum([x[j] for j in km[i]]) / len(km[i])
            _y = sum([y[j] for j in km[i]]) / len(km[i])
            k_new.append([_x, _y])
        k_new.sort()        #排序


4 循环2到3直到每个聚类不再发生变化为止


        frames.append(imageio.imread('1.jpg'))
        if (k_new != k_point):#一直循环直到聚类中心没有变化
            k_point = k_new
        else:
            return km
python完整代码实现

# coding:utf-8
import numpy as np
import pylab as pl
import random as rd
import imageio
#计算平面两点的欧氏距离
step=0
color=['.r','.g','.b','.y']#颜色种类
dcolor=['*r','*g','*b','*y']#颜色种类
frames = []
def distance(a, b):
    return (a[0]- b[0]) ** 2 + (a[1] - b[1]) ** 2
#K均值算法
def k_means(x, y, k_count):
    count = len(x)      #点的个数
    #随机选择K个点
    k = rd.sample(range(count), k_count)
    k_point = [[x[i], [y[i]]] for i in k]   #保证有序
    k_point.sort()
    global frames
    global step
    while True:
        km = [[] for i in range(k_count)]      #存储每个簇的索引
        #遍历所有点
        for i in range(count):
            cp = [x[i], y[i]]                   #当前点
            #计算cp点到所有质心的距离
            _sse = [distance(k_point[j], cp) for j in range(k_count)]
            #cp点到那个质心最近
            min_index = _sse.index(min(_sse))   
            #把cp点并入第i簇
            km[min_index].append(i)
        #更换质心
        step+=1
        k_new = []
        for i in range(k_count):
            _x = sum([x[j] for j in km[i]]) / len(km[i])
            _y = sum([y[j] for j in km[i]]) / len(km[i])
            k_new.append([_x, _y])
        k_new.sort()        #排序
 
        #使用Matplotlab画图
        pl.figure()
        pl.title("N=%d,k=%d  iteration:%d"%(count,k_count,step))
        for j in range(k_count):
            pl.plot([x[i] for i in km[j]], [y[i] for i in km[j]], color[j%4])
            pl.plot(k_point[j][0], k_point[j][1], dcolor[j%4])
        pl.savefig("1.jpg")
        frames.append(imageio.imread('1.jpg'))
        if (k_new != k_point):#一直循环直到聚类中心没有变化
            k_point = k_new
        else:
            return km
 
 
x, y = np.loadtxt('2.csv', delimiter=',', unpack=True)
k_count = 4
 
km = k_means(x, y, k_count)
print step
imageio.mimsave('k-means.gif', frames, 'GIF', duration = 0.5)
实验结果

初始值选取的不同造成结果也不一样
在这里插入图片描述
在这里插入图片描述

k-medoid(k中心点)

与K-means对比

k-means算法有个很大的缺点,就是对孤立点敏感性太高,孤立点即是脱离群众的点,与众不同的点,即在显示中与其他点不是抱在一团的点。

k-means算法

一开始的所有点:(可以看出其他点是混在一起有许多分类的)
在这里插入图片描述
使用k-means算法运行,定义3个中心点:
在这里插入图片描述
的确是被分成了三类,只不过两个孤立点算在了一类

k中心点算法

初始:
在这里插入图片描述
运算之后:
在这里插入图片描述
验证了k中心点算法的优越之处

不存在孤立点时候的k中心点算法的表现:

依然是一个类,只要传入初始点的个数要定义的中心点个数,便可以画出一开始杂乱无序的图和经过k中心点算法训练后的图。一开始,定义一千个点
在这里插入图片描述

十分杂乱,运行算法后的效果
在这里插入图片描述
不存在孤立点的情况,分出的效果与k-means算法还是差不多,如下为k-means运行的效果
在这里插入图片描述

k中心点算法python代码


# -*- coding: utf-8 -*-
# @Time    : 18-12-6
# @Author  : lin
 
from sklearn.datasets import make_blobs
from matplotlib import pyplot
import numpy as np
import random
 
 
class KMediod():
    """
    实现简单的k-medoid算法
    """
    def __init__(self, n_points, k_num_center):
        self.n_points = n_points
        self.k_num_center = k_num_center
        self.data = None
 
    def get_test_data(self):
        """
        产生测试数据, n_samples表示多少个点, n_features表示几维, centers
        得到的data是n个点各自坐标
        target是每个坐标的分类比如说我规定好四个分类,target长度为n范围为0-3,主要是画图颜色区别
        :return: none
        """
        self.data, target = make_blobs(n_samples=self.n_points, n_features=2, centers=self.n_points)
        np.put(self.data, [self.n_points, 0], 500, mode='clip')
        np.put(self.data, [self.n_points, 1], 500, mode='clip')
        pyplot.scatter(self.data[:, 0], self.data[:, 1], c=target)
        # 画图
        pyplot.show()
 
    def ou_distance(self, x, y):
        # 定义欧式距离的计算
        return np.sqrt(sum(np.square(x - y)))
 
    def run_k_center(self, func_of_dis):
        """
        选定好距离公式开始进行训练
        :param func_of_dis:
        :return:
        """
        print('初始化', self.k_num_center, '个中心点')
        indexs = list(range(len(self.data)))
        random.shuffle(indexs)  # 随机选择质心
        init_centroids_index = indexs[:self.k_num_center]
        centroids = self.data[init_centroids_index, :]   # 初始中心点
        # 确定种类编号
        levels = list(range(self.k_num_center))
        print('开始迭代')
        sample_target = []
        if_stop = False
        while(not if_stop):
            if_stop = True
            classify_points = [[centroid] for centroid in centroids]
            sample_target = []
            # 遍历数据
            for sample in self.data:
                # 计算距离,由距离该数据最近的核心,确定该点所属类别
                distances = [func_of_dis(sample, centroid) for centroid in centroids]
                cur_level = np.argmin(distances)
                sample_target.append(cur_level)
                # 统计,方便迭代完成后重新计算中间点
                classify_points[cur_level].append(sample)
            # 重新划分质心
            for i in range(self.k_num_center):  # 几类中分别寻找一个最优点
                distances = [func_of_dis(point_1, centroids[i]) for point_1 in classify_points[i]]
                now_distances = sum(distances)   # 首先计算出现在中心点和其他所有点的距离总和
                for point in classify_points[i]:
                    distances = [func_of_dis(point_1, point) for point_1 in classify_points[i]]
                    new_distance = sum(distances)
                    # 计算出该聚簇中各个点与其他所有点的总和,若是有小于当前中心点的距离总和的,中心点去掉
                    if new_distance < now_distances:
                        now_distances = new_distance
                        centroids[i] = point    # 换成该点
                        if_stop = False
        print('结束')
        return sample_target
 
    def run(self):
        """
        先获得数据,由传入参数得到杂乱的n个点,然后由这n个点,分为m个类
        :return:
        """
        self.get_test_data()
        predict = self.run_k_center(self.ou_distance)
        pyplot.scatter(self.data[:, 0], self.data[:, 1], c=predict)
        pyplot.show()
 
 
test_one = KMediod(n_points=1000, k_num_center=3)
test_one.run()
 

DBSCAN

简介

算法思想

DBSCAN这类基于密度的算法更像是人眼观察的分类结果,他对于处理不规则形状的分布和噪点都有较好的效果。这个算法将数据集中的点分为核心点、边缘点和噪点(如下图),然后根据自己定义的邻域进行划分。
    在这里插入图片描述

这里面,ε邻域表示所有到某xi点距离小于ε的集合,核心对象指其邻域中数据点多于阈值的点,其中,相同邻域的点为密度直达(下图左p,q),通过相同邻域的点能与其他邻域的点相联系的点称为密度可达(下图右p,q)。
    在这里插入图片描述

算法流程

整个算法就是将所有密度可达的点分为一个簇,不断寻找密度可达的点,没有则更改对象点,再开始下一个簇。
    在这里插入图片描述

算法优缺点

优点:
        · 对噪点不敏感
        · 能划分任意不同形状
缺点:
        · 聚类的结果会受到初始设定的参数影响。对于稀疏程度不同的数据集,相同的判定标准会破坏聚类的结构。

高斯混合模型(GMM)

简介

1、高斯分布
    高斯分布有时也被称作正态分布,是满足自然规律的一种常见的数据分布情况。  
     高斯分布的概率密度函数公式计算如下:
     其中μ为均值,σ表示标准差
 其中μ为均值,σ表示标准差

GMM

对于高斯混合模型,计算公式可写成:
    在这里插入图片描述
其中N()表示某一个分量,这个分量个数K是根据数据可以分成几个簇设定的。其中πk可以看成加权平均的权重,且所有πk之和为1,并且πk大于零。
    从计算公式中可以看出,会出现K个π、μ、Σ未知数。因为在计算时是随机从图中选择分量取点,那么如何确定所取点来自哪一个簇也就是确定π值则成为一个问题。这里用到了EM(Expectation-Maximization)算法来计算参数。

计算过程

说明EM计算参数之前,先利用贝叶斯思想对原式进行处理。
    在这里插入图片描述
通过定理中增加的参数可以看出,引入了一个隐含参数z用来描述之前提到的归属哪一个分量的问题,同时引入后验概率用于计算π、μ、Σ。
    EM算法大致分两步,第一步先计算需求参数的粗略值,第二步使用第一步的值最大化似然函数。
    
    EM算法:
1、根据数据定义分量数K,然后计算在这里插入图片描述
的对数似然函数。
2、根据当前的πk、μk、Σk计算后验概率。
在这里插入图片描述

3、根据第2步计算得到的后验概率计算新的πk、μk、Σk
在这里插入图片描述
  其中:
  在这里插入图片描述

4、检查参数是否收敛或对数似然函数是否收敛,若不收敛,则返回第2步。

GMM相较于K-means的优势

1、灵活。根据标准差参数,GMM可以采用任意椭圆形状而不是单一的圆形。K-means实际是GMM的一个特例。

2、由于GMM提供的不是一个硬性的聚类,而是一个概率,每个数据点可以有多个聚类。所以对于处于两个簇交叉区域的点可以给两个概率分别表示它属于某一个类的概率。

层次聚类

简介

层次聚类可以分成自上而下或自下而上两种,自下而上是先将每个样本视为自己一类,然后进行依次向上聚合,又称为凝聚,自上而下则是先视为一类,在进行细分。
    下图展示了自下而上的聚类动态过程
    在这里插入图片描述

层次聚类不需要指定聚类的数量,并且对距离度量的选择不敏感。但效率很低,时间复杂度为O(n3)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值