canopy算法流程_python实现Canopy算法

本文介绍了Canopy算法,一种用于预处理K-means和层次聚类的无监督算法,旨在加速大型数据集的聚类操作。文章通过Python代码展示了Canopy算法的实现过程,包括设置两个距离阈值T1和T2,以及核心的聚类步骤。最后,提供了数据可视化的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Canopy聚类

前两个月在做项目突然发现Canopy算法发现网上直接用python实现的不多,因为Mahout已经包含了这个算法,需要使用的时候仅需要执行Mahout几条命令即可,并且多数和MapReduce以及Hadoop分布式框架一起使用,感兴趣的可以在网上查阅。但出于学习和兴趣的态度,我更想尝试用python来亲自实现一些底层算法。

简介

The canopy clustering algorithm is an unsupervised pre-clustering algorithm introduced by Andrew McCallum, Kamal Nigam and Lyle Ungar in 2000.[1]

It is often used as preprocessing step for the K-means algorithm or the Hierarchical clustering algorithm. It is intended to speed up clustering operations on large data sets, where using another algorithm directly may be impractical due to the size of the data set.

以上面出自于维基百科.

Canopy算法是2000年由Andrew McCallum, Kamal Nigam and Lyle Ungar提出来的,它是对k-means聚类算法和层次聚类算法的预处理。众所周知,kmeans的一个不足之处在于k值需要通过人为的进行调整,后期可以通过肘部法则(Elbow Method)和轮廓系数(Silhouette Coefficient)来对k值进行最终的确定,但是这些方法都是属于“事后”判断的,而Canopy算法的作用就在于它是通过事先粗聚类的方式,为k-means算法确定初始聚类中心个数和聚类中心点。

Canopy算法过程:

The algorithm proceeds as follows, using two thresholds

T1 (the loose distance) and T2(the tight distance), whereT1>T2[1][2]

1.Begin with the set of data points to be clustered.

2.Remove a point from the set, beginning a new 'canopy'.

3.For each point left in the set, assign it to the new canopy if the distance less than the loose distance T1.

4.If the distance of the point is additionally less than the tight distance T2, remove it from the original set.

5.Repeat from step 2 until there are no more data points in the set to cluster.

6.These relatively cheaply clustered canopies can be sub-clustered using a more expensive but accurate algorithm.

代码实现

使用的包:

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

# @Author: Alan Lau

# @Date: 2017-09-05 22:56:16

# @Last Modified by: Alan Lau

# @Last Modified time: 2017-09-05 22:56:16

import math

import random

import numpy as np

from datetime import datetime

from pprint import pprint as p

import matplotlib.pyplot as plt

1.首先我在算法中预设了一个二维(为了方便后期画图呈现在二维平面上)数据dataset。当然也可以使用高纬度的数据,并且我将canopy核心算法写入了类中,后期可以通过直接调用的方式对任何维度的数据进行处理,当然只是小批量的,大批量的数据可以移步Mahout和Hadoop了,反正我的算法肯定没它们好哈哈。

# 随机生成500个二维[0,1)平面点

dataset = np.random.rand(500, 2)

2.然后生成个类,类的属性如下

class Canopy:

def __init__(self, dataset):

self.dataset = dataset

self.t1 = 0

self.t2 = 0

加入设定t1和t2初始值以及判断大小函数

# 设置初始阈值

def setThreshold(self, t1, t2):

if t1 > t2:

self.t1 = t1

self.t2 = t2

else:

print('t1 needs to be larger than t2!')

3.距离计算,各个中心点之间的距离计算方法我使用的欧式距离。

# 使用欧式距离进行距离的计算

def euclideanDistance(self, vec1, vec2):

return math.sqrt(((vec1 - vec2)**2).sum())

4.再写个从dataset中根据dataset的长度随机选择下标的函数

# 根据当前dataset的长度随机选择一个下标

def getRandIndex(self):

return random.randint(0, len(self.dataset) - 1)

5.核心算法

def clustering(self):

if self.t1 == 0:

print('Please set the threshold.')

else:

canopies = [] # 用于存放最终归类结果

while len(self.dataset) != 0:

rand_index = self.getRandIndex()

current_center = self.dataset[rand_index] # 随机获取一个中心点,定为P点

current_center_list = [] # 初始化P点的canopy类容器

delete_list = [] # 初始化P点的删除容器

self.dataset = np.delete(

self.dataset, rand_index, 0) # 删除随机选择的中心点P

for datum_j in range(len(self.dataset)):

datum = self.dataset[datum_j]

distance = self.euclideanDistance(

current_center, datum) # 计算选取的中心点P到每个点之间的距离

if distance < self.t1:

# 若距离小于t1,则将点归入P点的canopy类

current_center_list.append(datum)

if distance < self.t2:

delete_list.append(datum_j) # 若小于t2则归入删除容器

# 根据删除容器的下标,将元素从数据集中删除

self.dataset = np.delete(self.dataset, delete_list, 0)

canopies.append((current_center, current_center_list))

return canopies

为了方便后面的数据可视化,我这里的canopies定义的是一个数组,当然也可以使用dict。

6.main()函数

def main():

t1 = 0.6

t2 = 0.4

gc = Canopy(dataset)

gc.setThreshold(t1, t2)

canopies = gc.clustering()

print('Get %s initial centers.' % len(canopies))

#showCanopy(canopies, dataset, t1, t2)

Canopy聚类可视化代码

def showCanopy(canopies, dataset, t1, t2):

fig = plt.figure()

sc = fig.add_subplot(111)

colors = ['brown', 'green', 'blue', 'y', 'r', 'tan', 'dodgerblue', 'deeppink', 'orangered', 'peru', 'blue', 'y', 'r',

'gold', 'dimgray', 'darkorange', 'peru', 'blue', 'y', 'r', 'cyan', 'tan', 'orchid', 'peru', 'blue', 'y', 'r', 'sienna']

markers = ['*', 'h', 'H', '+', 'o', '1', '2', '3', ',', 'v', 'H', '+', '1', '2', '^',

'', '.', '4', 'H', '+', '1', '2', 's', 'p', 'x', 'D', 'd', '|', '_']

for i in range(len(canopies)):

canopy = canopies[i]

center = canopy[0]

components = canopy[1]

sc.plot(center[0], center[1], marker=markers[i],

color=colors[i], markersize=10)

t1_circle = plt.Circle(

xy=(center[0], center[1]), radius=t1, color='dodgerblue', fill=False)

t2_circle = plt.Circle(

xy=(center[0], center[1]), radius=t2, color='skyblue', alpha=0.2)

sc.add_artist(t1_circle)

sc.add_artist(t2_circle)

for component in components:

sc.plot(component[0], component[1],

marker=markers[i], color=colors[i], markersize=1.5)

maxvalue = np.amax(dataset)

minvalue = np.amin(dataset)

plt.xlim(minvalue - t1, maxvalue + t1)

plt.ylim(minvalue - t1, maxvalue + t1)

plt.show()

可视化结果

我把每个点都染上了其归属聚类中心点的颜色,还是挺漂亮的,这就是所谓的数据之美吧...

当然也有人问,t1和t2的初始值如何设定,后期的聚类中心点完全依赖这两个值的变化。t1和t2可以通过交叉验证的方式获得,具体怎么做,得视乎数据以及用户的需求,具体可以参考相关的论文。

Github链接

下面是 Canopy 算法Python 实现: ```python import numpy as np def euclidean_distance(point1, point2): """计算欧几里得距离""" return np.sqrt(np.sum((point1 - point2) ** 2)) def canopy(data, t1, t2): """Canopy 算法实现""" # 初始化两个空列表,用于存放簇中心点和未被选择的数据点 centers = [] unselected = list(range(len(data))) while unselected: # 随机从未被选择的数据点中选择一个作为当前簇的中心点 center_index = np.random.choice(unselected) center_point = data[center_index] current_center = [center_index] # 将当前中心点从未被选择的点中删除 unselected.remove(center_index) # 计算当前中心点与所有未被选择的点之间的距离,将距离小于等于 t1 的点加入当前簇 for index in unselected: point = data[index] distance = euclidean_distance(center_point, point) if distance <= t1: current_center.append(index) # 将当前簇中心点加入簇中心点列表 centers.append(center_point) # 将当前簇中的点从未被选择的点中删除 for index in current_center: unselected.remove(index) # 对于剩余未被选择的点,计算与当前簇中心点之间的距离,如果距离小于等于 t2,将该点加入当前簇 while unselected: index = unselected[0] point = data[index] distance = euclidean_distance(center_point, point) if distance <= t2: current_center.append(index) unselected.remove(index) else: break return centers ``` 其中,`data` 为输入数据,`t1` 和 `t2` 为 Canopy 算法的两个参数,分别表示最小簇半径和最大簇半径。`euclidean_distance` 函数用于计算欧几里得距离。在主函数 `canopy` 中,首先将所有数据点标记为未被选择的点,然后随机选择一个点作为当前簇的中心点。接着,计算当前中心点与所有未被选择的点之间的距离,将距离小于等于 t1 的点加入当前簇,并将当前中心点从未被选择的点中删除。然后将当前簇中心点加入簇中心点列表,并将当前簇中的点从未被选择的点中删除。对于剩余未被选择的点,计算与当前簇中心点之间的距离,如果距离小于等于 t2,将该点加入当前簇,直到没有点可以加入为止。最后返回所有簇的中心点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值