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)以及可能的样本大小(如果使用了抽样技术)。
2. 迭代过程
重复迭代:对于每次迭代,执行以下步骤:
随机选择替换对象:从当前medoids中随机选择一个进行替换。
随机选择候选点:从数据集中随机选择一个非medoid点作为候选替换点。
计算代价:计算替换前后的聚类代价(如总距离平方和)。
更新medoids:如果替换后的代价更小,则更新medoids集合;否则,保持原样。
多次尝试替换:在每次迭代中,重复上述替换过程max_neighbor次,以尝试找到更好的聚类中心。
记录最佳medoids:在每次迭代结束时,记录当前找到的最佳medoids(即代价最小的medoids)。
继续迭代:直到达到最大迭代次数max_iter。
3. 输出结果
输出最佳medoids:在所有迭代结束后,输出最终找到的最佳medoids。
分配簇:根据最佳medoids,将每个数据点分配给最近的medoid,形成最终的簇。
4. 评估聚类质量
计算聚类质量指标:如轮廓系数(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算法的随机性,你可能需要多次运行算法并选择最佳结果,或者使用交叉验证来评估聚类质量的稳定性。