首页 > 编程语言 >CLARANS算法原理及Python实践

CLARANS算法原理及Python实践

时间:2024-08-28 19:58:28浏览次数:11  
标签:medoids Python CLARANS sample 算法 聚类 np clusters

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算法的随机性,你可能需要多次运行算法并选择最佳结果,或者使用交叉验证来评估聚类质量的稳定性。

标签:medoids,Python,CLARANS,sample,算法,聚类,np,clusters
From: https://blog.csdn.net/u013571432/article/details/141648332

相关文章