统计学习方法笔记-聚类方法

一 什么是聚类

聚类是针对给定的样本,依据它们的特征的相似度或距离,将其归并到若干"类" 或者 "簇"的数据分析问题,直观上讲,聚类是将相似的样本归到一个类。

根据介绍我们明白,聚类的核心是如何来对两个样本的相似度来进行度量。聚类方法有多种度量方法,下面一起来看看吧。

二 相似度的度量方法

在聚类中,可以将样本集合看作是向量空间中点的集合,利用点和点之间的距离来代表样本与样本之间的相似度。点与点之间距离越近,则样本与样本的相似度越高。

下面来介绍几种距离度量

闵可夫斯基距离

给定样本集合X, X是m维实数向量空间Rm中点的集合,其中xi,xj ∈X,xi=(x1i,x2i,…,xmi)T,xj=(x1j,x2j,…,xmj)T,样本xi与样本xj的闵可夫斯基距离定义为

在这里插入图片描述
其中当p=2时称为欧氏距离

在这里插入图片描述
当p=1时称为曼哈顿距离

在这里插入图片描述
当 p= ∞时称为切比雪夫距离, 取各个坐标数值差的绝对值的最大值,即

在这里插入图片描述

马哈拉诺比斯距离

马哈拉诺比斯距离简称马氏距离,它考虑各个分量(也就是样本的特征)之间的相关性,并且与各个分量的尺度无关。

给定一个样本集合 X,X = (xij)m*n,,其协方差矩阵记作 S。样本xi 与样本xj之间的马哈拉诺比斯距离 dij 定义为

在这里插入图片描述X的协方差矩阵是这样定义的:

设X=(X1,X2,…XN)T 则矩阵

在这里插入图片描述为n维随机变量X的协方差矩阵,其中cij=Cov(Xi,Xj) i,j=1,2,…n 为 X的分量Xi,Xj的协方差。

除了距离度量,还可以用相关系数和夹角余弦来度量样本间的相似度

相关系数

样本 xi与样本 xj之间的相关系数定义为
在这里插入图片描述
其中

在这里插入图片描述
夹角余弦

样本与样本之间的夹角越小,即夹角余弦越趋于1,两个样本的相似度越高。 样本与样本之间的夹角越大,即夹角余弦越趋于0,两个样本的相似度越低。

样本 xi 与样本 xj之间的夹角余弦定义为
在这里插入图片描述
在这里插入图片描述在上图中,A与C之间的夹角相比于B与C之间的夹角更小,所以A相对与B来讲与C更相似。

三 聚类方法

下面介绍两个聚类方法。

层次聚类

主要介绍层次聚类中的聚合聚类。

聚合聚类开始将每个样本各自分到一个类:之后将相距最近的两类合并,建立一 个新的类,重复此操作,每次减少一个类,直到满足停止条件。

聚合聚类算法如下:
在这里插入图片描述代码实现

class Hierarchical_Clutering:
    def __init__(self,Train):
        self.Train=Train
        self.M=self.Train.shape[1] #样本的维数
        self.N=self.Train.shape[0] #样本的个数
        self.D=self.cal_D()
        self.classes,self.class_index=self.generating_classes() #类集合

    def Minkowski_distance(self,X,Y,p):
        #闵可夫斯基距离
        max=0
        d=0
        if p>sys.maxsize: #如果p是无穷 即切比雪夫距离
            for i in range(self.M):
                if math.fabs(X[i]-Y[i]) > max:
                    max=math.fabs(X[i]-Y[i])
            d=max
        else:
            sum=0
            for i in range(self.M):
                sum+=math.pow(math.fabs(X[i]-Y[i]),p)
            d=math.pow(sum,1/p)
        return d

    def cal_D(self):
     #计算n个样本两两之间的欧氏距离
     D=[[0]*self.N]*self.N
     for i in range(self.N):
         for j in range(i+1,self.N):
             d=self.Minkowski_distance(self.Train[i],self.Train[j],2)
             D[i][j]=d
             D[j][i]=d
     return D

    def generating_classes(self):
     #构造n个类,使每个类只包含一个样本
         classes={}
         class_index=[]
         for i in range(self.N):
             classes[i]=[]
             classes[i].append((i,self.Train[i])) #i 表示第几个样本 self.Train[i] 是样本的内容
             class_index.append(i) #类别
         return classes,class_index

    def fit(self):
        lens=len(self.classes)
        min_c1=0
        min_c2=0
        while len(self.classes)>1: #类的总数大于等于2 就可以继续合并
           print(self.classes)
           l=len(self.class_index)
           print(self.class_index)
           min_dis = sys.maxsize
           for i in range(l):
              for j in range(i+1,l):
                  c1_num=self.class_index[i]
                  c2_num=self.class_index[j]
                  class1=self.classes[c1_num]
                  class2=self.classes[c2_num]
                  for c1 in range(len(class1)):
                      for c2 in range(len(class2)):
                           d=self.D[class1[c1][0]][class2[c2][0]]
                           if d <min_dis:
                               min_dis=d
                               min_c1= c1_num
                               min_c2= c2_num
           for c in self.classes[min_c2]:
              #print(c)
              self.classes[min_c1].append(c)
           del self.classes[min_c2]
           self.class_index.remove(min_c2)


train=np.array([[0,2],
                [0,0],
                [1,0],
                [5,0],
                [5,2]])
model=Hierarchical_Clutering(train)
model.fit()

K均值聚类

K均值聚类是将样本集合划分为K个子集,也就是构成K个类,每一个类都有一个中心点。K均值聚类划分的原则是将每一个样本点划分到离它最近的那个中心点所代表的类。

1 距离度量

K均值聚类算法采用欧氏距离的平方作为样本之间的距离 即

在这里插入图片描述
2 损失函数

我们知道两个样本的欧氏距离越小则其相似度越高。所以当确定了K个类的中心之后,我们将其他样本进行聚类的方法就是将某个样本聚到离它最近的中心点所代表的类,也就是让所有样本到其所在类的中心点的距离之和最小,基于此建立损失函数。

在这里插入图片描述在这里插入图片描述3 K均值聚类算法

(1) 对于给定训练集,首先要随机选择K个样本作为中心点。

(2) 对样本进行聚类: 对于每一个样本,计算它到所有中心点的距离,选取距离最近的中心点,将该样本点划分到该中心点所在的类。

(3) 计算新的类的中心: 聚类完毕后,我们要计算每一类的均值,以此均值作为每一类的新的中心

重复以上 2,3 过程直到满足终止条件

终止条件可以是迭代次数到达某一个阈值,或者划分结果不再改变。

4 代码实现

class Kmeans:
    def __init__(self,Train,K):
        self.Train=Train
        self.K=K #K个中心
        #self.M=M #进行M次迭代
        self.center=self.generate_initial_center()
        self.classes={}

    def Minkowski_distance(self, X, Y, p):
        # 闵可夫斯基距离
        max = 0
        d = 0
        if p > sys.maxsize:  # 如果p是无穷 即切比雪夫距离
            for i in range(self.train.shape[1]):
                if math.fbs(X[i] - Y[i]) > max:
                    max = math.fabs(X[i] - Y[i])
            d = max
        else:
            sum = 0
            for i in range(self.Train.shape[1]):
                sum += math.pow(math.fabs(X[i] - Y[i]), p)
            d = math.pow(sum, 1 / p)
        return d

    def generate_initial_center(self):
        #随机选择k个样本点作为初始样本点
        i=0
        c=[]
        center={}
        while i< self.K:
            a=random.randint(0,self.Train.shape[0]-1) #随机选择一个样本序号
            if a not in c: #为避免重复选择某一个顶点
                center[i]=self.Train[a]
                c.append(a)
                i+=1
        return center

    def fit(self):
        for k in range(self.K):
            self.classes[k]=[]
        isContinue=True
        #for m in range(self.M):
        while isContinue:
           isContinue=False
           for i in range(self.Train.shape[0]): #为每个样本找离它最近的中心点以此分类
              min_dis=sys.maxsize
              min_k=0
              for k in range(self.K):
                d=(self.Minkowski_distance(self.Train[i],self.center[k],2))**2
                if d < min_dis:
                    min_dis=d
                    min_k=k
              self.classes[min_k].append(self.Train[i])
           for k in range(self.K):
              print("k= "+str(k))
              print("更新前")
              print(self.center[k])
              list=self.classes[k]
              lens=len(list) #这个类一共有多少个样本
              array=np.array(list) #转换为矩阵
              means=np.sum(array, axis=0)/lens #更新中心点
              if any(means!=self.center[k]):
                self.center[k]=means
                isContinue=True
              print("更新后")
              print(self.center[k])
              self.classes[k]=[]
              print("*******************")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值