CLARANS算法原理及Python实践

CLARANS(Clustering Algorithm based on Randomized Search)算法是一种基于随机搜索的聚类算法,主要用于处理大规模数据集的聚类问题。该算法结合了CLARA(Clustering Large Applications based on Randomized Approach)算法和PAM(Partitioning Around Medoids)算法的思想,通过随机采样和迭代优化来寻找最优的聚类中心。

一、CLARANS算法原理概述

CLARANS算法的核心思想是在搜索过程中引入随机性,通过多次随机选择样本和聚类中心,以找到全局最优或接近全局最优的聚类结果。其基本原理可以归纳为以下几个步骤:

1、随机采样:从原始数据集中随机选择一部分数据作为样本,用于后续的聚类分析。这一步的目的是减少计算量,提高算法的效率。

2、初始化聚类中心:从样本中随机选择若干个数据点作为初始聚类中心。这些聚类中心将作为后续迭代的起点。

3、随机替换聚类中心:在每次迭代中,算法会随机选择一个非聚类中心的数据点,并尝试用它来替换当前的某个聚类中心。替换后,重新计算每个数据点到新聚类中心的距离,并根据距离重新分配数据点到最近的聚类中心。

4、评估聚类质量:通过某种评估指标(如总距离平方和)来衡量聚类质量。如果替换后的聚类质量有所改善(即评估指标值减小),则接受这次替换;否则,放弃替换,并尝试下一次随机替换。

5、重复迭代:重复步骤3和步骤4,直到达到预定的迭代次数或聚类质量不再显著改善为止。

6、输出聚类结果:最终,算法会输出一组聚类中心,以及每个数据点所属的聚类。

二、CLARANS算法的优点与局限性

1、优点:

(1)处理大规模数据集:CLARANS算法通过随机采样和迭代优化,能够有效地处理大规模数据集,具有较好的可伸缩性。

(2)改进的聚类质量:与传统的K-MEDOIDS算法相比,CLARANS算法通过随机搜索策略,能够在一定程度上提高聚类质量。

2、局限性:

(1)计算效率较低:由于引入了随机搜索策略,CLARANS算法的计算效率相对较低,尤其是在处理大规模数据集时。

(2)对数据输入顺序敏感:CLARANS算法的性能可能受到数据输入顺序的影响,这可能导致算法在不同数据集上的表现存在差异。

(3)只能聚类凸状或球型边界:CLARANS算法在聚类形状复杂的数据集时可能效果不佳,因为它主要适用于凸状或球型边界的数据分布。

综上所述,CLARANS算法是一种基于随机搜索的聚类算法,通过随机采样和迭代优化来寻找最优的聚类中心。该算法在处理大规模数据集时具有较好的可伸缩性,但计算效率较低且对数据输入顺序敏感。在实际应用中,需要根据具体的数据集和聚类需求来选择合适的聚类算法。

三、CLARANS算法的Python实践

在Python中实现CLARANS(Clustering Algorithm based on Randomized Search)算法可以从头开始编写,但考虑到其复杂性和可能的优化需求,通常会使用一些现成的库或框架作为基础,或者参考现有的伪代码进行实现。然而,由于CLARANS算法不是像K-means或DBSCAN那样广泛内置于Python的聚类库中,你可能需要自己编写其核心部分。

以下是一个简化的CLARANS算法实现框架,用于说明其基本思路。请注意,这个实现是为了教学目的而简化的,并未进行优化,可能不适用于大规模数据集。

import numpy as np

from sklearn.metrics.pairwise import euclidean_distances

def init_medoids(X, k, sample_size=None):

"""随机初始化k个medoids(聚类中心)"""

if sample_size is None:

sample_size = X.shape[0]

indices = np.random.choice(X.shape[0], sample_size, replace=False)

sample = X[indices]

medoids_idx = np.random.choice(sample_size, k, replace=False)

return sample[medoids_idx]

def assign_clusters(X, medoids):

"""将每个点分配给最近的medoid"""

distances = euclidean_distances(X, medoids)

clusters = np.argmin(distances, axis=1)

return clusters

def swap_medoid(X, clusters, medoids, idx_to_swap):

"""尝试用一个非medoid点替换一个medoid点,并重新分配簇"""

选择一个非medoid点

swap_candidates = np.setdiff1d(np.arange(X.shape[0]), np.arange(len(medoids)))

swap_idx = np.random.choice(swap_candidates)

尝试替换

new_medoids = np.copy(medoids)

new_medoids[idx_to_swap] = X[swap_idx]

重新分配簇

new_clusters = assign_clusters(X, new_medoids)

计算新聚类的总距离平方和(或其他评估指标)

cost_new = np.sum(euclidean_distances(X[new_clusters], new_medoids[new_clusters])**2)

cost_old = np.sum(euclidean_distances(X[clusters], medoids[clusters])**2)

如果新聚类更优,则返回新medoids和簇;否则,返回原medoids和簇

if cost_new < cost_old:

return new_medoids, new_clusters

else:

return medoids, clusters

def clarans(X, k, max_iter=100, sample_size=None):

"""CLARANS算法实现"""

medoids = init_medoids(X, k, sample_size)

clusters = assign_clusters(X, medoids)

for _ in range(max_iter):

随机选择一个medoid进行替换

idx_to_swap = np.random.randint(k)

medoids, clusters = swap_medoid(X, clusters, medoids, idx_to_swap)

return medoids, clusters

示例使用

假设X是你的数据集,这里用随机数据代替

np.random.seed(0)

X = np.random.rand(100, 2) # 100个样本,每个样本2个特征

k = 3 # 假设我们想将数据聚类成3个簇

medoids, clusters = clarans(X, k, max_iter=100, sample_size=50)

print("找到的medoids:", medoids)

print("聚类结果:", clusters)

请注意,上述代码中的swap_medoid函数仅尝试替换一个medoid,并且没有考虑所有可能的替换组合。在真正的CLARANS算法中,你可能会想在一个迭代中尝试多个替换,或者在不同的迭代中尝试不同的替换策略。

此外,为了优化性能,你可以考虑使用更高效的数据结构(如KD树或球树)来加速最近邻搜索。然而,在Python的sklearn库中,euclidean_distances函数通常已经足够快,除非你在处理非常大的数据集。

最后,请注意,由于CLARANS算法的随机性,每次运行算法时得到的聚类结果可能会有所不同。你可能需要运行算法多次并选择最佳结果,或者使用某种形式的交叉验证来评估聚类质量的稳定性在继续讨论CLARANS算法的Python实践时,我们需要明确几个关键点,包括算法的随机性、迭代过程、以及如何评估聚类质量。以下是一个更详细的CLARANS算法Python实现框架,该框架将考虑更多的迭代细节和随机性。

CLARANS算法Python实现框架

  1. 初始化

随机选择初始medoids:从数据集中随机选择k个数据点作为初始的聚类中心(medoids)。

设置参数:包括最大迭代次数(max_iter)、每次迭代中尝试的替换次数(max_neighbor)以及可能的样本大小(如果使用了抽样技术)。

  1. 迭代过程

重复迭代:对于每次迭代,执行以下步骤:

随机选择替换对象:从当前medoids中随机选择一个进行替换。

随机选择候选点:从数据集中随机选择一个非medoid点作为候选替换点。

计算代价:计算替换前后的聚类代价(如总距离平方和)。

更新medoids:如果替换后的代价更小,则更新medoids集合;否则,保持原样。

多次尝试替换:在每次迭代中,重复上述替换过程max_neighbor次,以尝试找到更好的聚类中心。

记录最佳medoids:在每次迭代结束时,记录当前找到的最佳medoids(即代价最小的medoids)。

继续迭代:直到达到最大迭代次数max_iter。

  1. 输出结果

输出最佳medoids:在所有迭代结束后,输出最终找到的最佳medoids。

分配簇:根据最佳medoids,将每个数据点分配给最近的medoid,形成最终的簇。

  1. 评估聚类质量

计算聚类质量指标:如轮廓系数(Silhouette Coefficient)、Calinski-Harabasz指数等,以评估聚类结果的质量。

Python实现示例(简化版)

请注意,以下代码是一个高度简化的示例,用于说明算法流程,并未进行完整的优化和错误处理。

import numpy as np

from sklearn.metrics.pairwise import euclidean_distances

def clarans(X, k, max_iter=100, max_neighbor=10, sample_size=None):

if sample_size is None:

sample_size = X.shape[0]

best_medoids = init_medoids(X, k, sample_size)

best_cost = float('inf')

for _ in range(max_iter):

current_medoids = np.copy(best_medoids)

for _ in range(max_neighbor):

随机选择一个medoid进行替换

idx_to_swap = np.random.randint(k)

随机选择一个非medoid点作为候选

swap_candidates = np.setdiff1d(np.arange(X.shape[0]), np.arange(k))

swap_idx = np.random.choice(swap_candidates)

尝试替换

new_medoids = np.copy(current_medoids)

new_medoids[idx_to_swap] = X[swap_idx]

重新分配簇并计算代价

clusters = assign_clusters(X, new_medoids)

cost = np.sum(euclidean_distances(X[clusters], new_medoids[clusters])**2)

更新最佳medoids(如果代价更小)

if cost < best_cost:

best_cost = cost

best_medoids = new_medoids

输出最终聚类结果

final_clusters = assign_clusters(X, best_medoids)

return best_medoids, final_clusters

辅助函数(如init_medoids和assign_clusters)与之前的示例相同,这里不再重复。

示例使用

np.random.seed(0)

X = np.random.rand(100, 2)

k = 3

medoids, clusters = clarans(X, k, max_iter=100, max_neighbor=10)

print("找到的medoids:", medoids)

print("聚类结果:", clusters)

请注意,这个实现假设整个数据集都被用作搜索空间,没有使用抽样技术。如果你想要使用抽样技术来减少计算量(如CLARA所做的那样),你需要在init_med在继续讨论CLARANS算法并使用抽样技术的Python实现时,我们需要对init_medoids`函数进行修改,以便它只从数据集的随机样本中选择初始medoids。此外,我们还需要确保在迭代过程中,候选的替换点也是从这个样本中随机选择的(尽管这通常不是必须的,但可以减少计算量)。然而,为了简单起见,并且保持算法的通用性,我们通常允许在整个数据集中搜索候选替换点。

以下是考虑了抽样技术的CLARANS算法Python实现的一个更完整的版本:

import numpy as np

from sklearn.metrics.pairwise import euclidean_distances

def init_medoids(X, k, sample_size):

"""从随机样本中初始化k个medoids"""

if sample_size is None or sample_size >= X.shape[0]:

sample_size = X.shape[0]

indices = np.random.choice(X.shape[0], sample_size, replace=False)

sample = X[indices]

medoids_idx = np.random.choice(sample_size, k, replace=False)

return sample[medoids_idx]

def assign_clusters(X, medoids):

"""将每个点分配给最近的medoid"""

distances = euclidean_distances(X, medoids)

clusters = np.argmin(distances, axis=1)

return clusters

def clarans(X, k, max_iter=100, max_neighbor=10, sample_size=None):

"""CLARANS算法实现,可选地使用抽样技术"""

if sample_size is None:

sample_size = X.shape[0] # 如果未指定样本大小,则使用整个数据集

best_medoids = init_medoids(X, k, sample_size)

best_cost = float('inf')

for _ in range(max_iter):

current_medoids = np.copy(best_medoids)

for _ in range(max_neighbor):

随机选择一个medoid进行替换

idx_to_swap = np.random.randint(k)

在整个数据集中搜索候选替换点(这里不使用抽样)

注意:为了效率,你也可以从样本中搜索,但这可能会牺牲一些解的质量

swap_candidates = np.arange(X.shape[0]) # 所有数据点的索引

swap_idx = np.random.choice(swap_candidates)

尝试替换

new_medoids = np.copy(current_medoids)

new_medoids[idx_to_swap] = X[swap_idx]

重新分配簇并计算代价

clusters = assign_clusters(X, new_medoids)

cost = np.sum(euclidean_distances(X[clusters], new_medoids[clusters])**2)

更新最佳medoids(如果代价更小)

if cost < best_cost:

best_cost = cost

best_medoids = new_medoids

输出最终聚类结果

final_clusters = assign_clusters(X, best_medoids)

return best_medoids, final_clusters

示例使用

np.random.seed(0)

X = np.random.rand(100, 2)

k = 3

medoids, clusters = clarans(X, k, max_iter=100, max_neighbor=10, sample_size=50)

print("找到的medoids:", medoids)

print("聚类结果:", clusters)

在这个实现中,init_medoids函数现在接受一个sample_size参数,该参数指定了从数据集中随机选择的样本大小。如果sample_size未指定或大于数据集的大小,则使用整个数据集。在迭代过程中,我们仍然在整个数据集上搜索候选替换点,但你可以根据需要将这部分修改为仅从样本中搜索。

请注意,这个实现并没有对算法进行过多的优化,特别是在处理大规模数据集时。在实际应用中,你可能需要考虑使用更高效的数据结构(如KD树或球树)来加速最近邻搜索,或者利用并行计算来加速迭代过程。此外,由于CLARANS算法的随机性,你可能需要多次运行算法并选择最佳结果,或者使用交叉验证来评估聚类质量的稳定性。

相关推荐
兆。几秒前
掌握 PyQt5:从零开始的桌面应用开发
开发语言·爬虫·python·qt
小刘|31 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
南宫理的日知录34 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
jjyangyou36 分钟前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
coberup43 分钟前
django Forbidden (403)错误解决方法
python·django·403错误
van叶~1 小时前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法1 小时前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
云卓SKYDROID1 小时前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
龙哥说跨境1 小时前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
小白学大数据1 小时前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin