ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python 不调包实现Hierarchical Clustering——层次聚类(合并法)

2021-07-28 21:59:17  阅读:254  来源: 互联网

标签:Clustering Python self 调包 shape 聚类 np hc



提示:本文不调用sklearn等包,直接使用numpy和pandas完成了Hierarchical Clustering,即层次聚类算法的实现。

文章目录


一、Hierarchical Clustering之算法原理

  1. 算法介绍
    首先呢,Hierarchical Clustering是属于无监督的聚类方法,具体来说又分为多种更细的方法,如合并法、分解法、树状图。本文主要实现的是合并法。而像常用的Kmeans并不属于层次聚类,而是属于非层次聚类。
  2. 算法原理
    Hierarchical Clustering中的合并法很好理解,先将样本划分为多个集合,然后计算两两集合之间的距离并构造距离矩阵D,具体来说每个集合的特征表示可以为集合内所有样本均值等多种方法,本文主要考虑取集合中样本均值作为集合的特征值,其他方法就不深究了。得到距离矩阵D之后,找出距离最小的两个集合并合并,然后更新距离矩阵D并执行下一次合并,直到所有集合的数量满足为自己所要的类别数量,算法停止。
  3. 具体实例(说人话)
    假设有n=1000条样本,最终聚类目标是m = 10个类别。那么将1000条样本划分为1000个集合,每个集合目前只包含一条样本。计算两两集合距离矩阵D,其维度是1000*1000,对角线上是0。找出D中的最小值min(D),并合并对应的行列所代表的样本,成为一个新的集合。此时集合数量为999个了,更新一下距离矩阵D,注意如果此处根据我写的代码重新计算则:
    计算复杂度= n2+(n-1)2+(n-2)2+…+(m+1)2=∑ (不太懂怎么码这个katex,看懂了就行吧)
    然后我就发现我1000条数据预估要跑半天,迭代实在是太慢了,在数据导入的时候使用了.sample(n=50),嘿嘿,这下子还是很快的。各位大佬们可以自己改一下矩阵更新的过程,保留上一次迭代大部分距离矩阵D的内容,只更新当次迭代进行了合并的集合,只有它们的距离发生了改变。

二、python源码

代码如下(示例):

1.Hierarchical Clustering.py

# -*- coding: utf-8 -*-

import pandas as pd
import numpy as np


class HC(object):

    def __init__(self, data,categorynums):
        self.Clustering_Data = data
        self.hc = []
        self.cnt = 0
        self.categorynums = categorynums
        self.start()

    def indmin_matrix(self, M):
        row, col = divmod(np.argmin(M), np.shape(M)[1])
        return row, col

    def em(self, A, B):
        efunc = lambda a, b: np.power(float(a) - float(b), 2)
        func = np.frompyfunc(efunc, 2, 1)
        em = np.sqrt(sum(func(A, B)))
        return em

    def AverageLinkage(self, A, B):
        total = 0.0
        for i in A:
            for j in B:
                total += self.em(i, j)
        ret = total / (np.shape(A)[0] * np.shape(B)[0])
        return ret

    def start(self):
        self.cnt += 1
        print('\n\n===================%d times Hierarical Clustring================' % self.cnt)
        # 首次进行算法,要初始化结果数组
        if 0 == np.shape(self.hc)[0]:
            initData = [[i] for i in range(np.shape(self.Clustering_Data)[0])]
            self.hc = [initData]
            print('init self.hc:', self.hc)
        preHC, n = self.hc[-1], np.shape(self.hc[-1])[0]
        print('preHC:', preHC)
        # 剩下的集合数量为categorynums时停止聚类
        if self.categorynums == n:
            print('succeed hierarical clustring:\n', )
            for i in range(np.shape(self.hc)[0]):
                print(self.hc[i])
            return self.hc
        # 继续聚类
        dist = np.full(shape=(n, n), fill_value=np.inf)
        value = np.array(self.Clustering_Data)[:, -1]
        for i in range(n):
            for j in np.arange(start=i + 1, stop=n, step=1):
                A, B = value[preHC[i]], value[preHC[j]]
                dist[i, j] = self.AverageLinkage(A, B)
        print('dist:\n', dist)
        # 更新聚类结果
        row, col = self.indmin_matrix(dist)
        C = []
        newHC = []
        for i in range(n):
            if row == i or col == i:
                if np.shape(C)[0] == 0:
                    C = preHC[row] + preHC[col]
                    newHC.append(C)
                continue
            newHC.append(preHC[i])
        # 更新HC结果数组
        self.hc.append(newHC)
        # for i in range(np.shape(self.hc)[0]):
        #     print(self.hc[i])
        return self.start()


if __name__ == '__main__':
    #n是采样数,建议值为100以下,否则运算太慢
    df = pd.read_csv('../../../../Tencent/2668630468/FileRecv/BWGHT.csv')
    df = df.fillna(0)
    df = df.reset_index()
    temp = np.linspace(0, df.shape[0], num=df.shape[0], endpoint=False)
    df['index'] = pd.DataFrame(temp, columns=['index'])
    data = []
    for i in range(df.shape[0]):
        templist = []
        linelist = list(df.loc[i][:].values)
        templist.append([linelist[-1]])
        templist.append(linelist[0:-2])
        data.append(templist)
    # 5是聚类结果的类别数量,可以自行设定
    hc = HC(data,5)

2.读入数据

CSDN数据链接如下:数据链接


总结

本文使用numpy完成了层次聚类的实现,层次聚类虽然简单但是复杂度极高,不过也可以加以优化,通过记录上次迭代的距离矩阵,避免更新一整个距离矩阵,速度会快上一些。

标签:Clustering,Python,self,调包,shape,聚类,np,hc
来源: https://blog.csdn.net/qq_40811682/article/details/119190471

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有