ML-From-Scratch项目解析:PAM聚类算法实现详解
什么是PAM算法
PAM(Partitioning Around Medoids)算法是一种经典的聚类算法,属于k-medoids聚类方法家族。与更广为人知的k-means算法不同,PAM算法使用实际数据点作为聚类中心(称为medoids),而不是计算均值点作为中心。这使得PAM算法对噪声和异常值具有更强的鲁棒性。
PAM算法核心思想
PAM算法的核心思想可以概括为两个阶段:
- 构建阶段(BUILD):随机选择k个样本作为初始medoids
- 交换阶段(SWAP):尝试用非medoids样本替换当前medoids,如果能够降低总成本(样本到其medoids的总距离),则接受替换
ML-From-Scratch中的PAM实现分析
1. 初始化随机medoids
def _init_random_medoids(self, X):
n_samples, n_features = np.shape(X)
medoids = np.zeros((self.k, n_features))
for i in range(self.k):
medoid = X[np.random.choice(range(n_samples))]
medoids[i] = medoid
return medoids
该方法从数据集中随机选择k个样本作为初始medoids。这种随机初始化方式简单直接,但可能导致算法收敛到局部最优解。在实际应用中,可以考虑使用更复杂的初始化策略,如k-means++的变种。
2. 寻找最近medoid
def _closest_medoid(self, sample, medoids):
closest_i = None
closest_distance = float("inf")
for i, medoid in enumerate(medoids):
distance = euclidean_distance(sample, medoid)
if distance < closest_distance:
closest_i = i
closest_distance = distance
return closest_i
该方法计算样本到所有medoids的欧氏距离,返回最近medoid的索引。欧氏距离是最常用的距离度量,但对于某些数据类型(如分类数据),可能需要使用其他距离度量。
3. 创建聚类
def _create_clusters(self, X, medoids):
clusters = [[] for _ in range(self.k)]
for sample_i, sample in enumerate(X):
medoid_i = self._closest_medoid(sample, medoids)
clusters[medoid_i].append(sample_i)
return clusters
该方法将每个样本分配到最近的medoid对应的簇中。注意这里存储的是样本的索引而不是样本本身,这可以减少内存使用。
4. 计算成本函数
def _calculate_cost(self, X, clusters, medoids):
cost = 0
for i, cluster in enumerate(clusters):
medoid = medoids[i]
for sample_i in cluster:
cost += euclidean_distance(X[sample_i], medoid)
return cost
成本函数是所有样本到其对应medoids的距离总和。PAM算法的目标就是最小化这个成本函数。
5. 主预测方法
def predict(self, X):
medoids = self._init_random_medoids(X)
clusters = self._create_clusters(X, medoids)
cost = self._calculate_cost(X, clusters, medoids)
while True:
best_medoids = medoids
lowest_cost = cost
for medoid in medoids:
non_medoids = self._get_non_medoids(X, medoids)
for sample in non_medoids:
new_medoids = medoids.copy()
new_medoids[medoids == medoid] = sample
new_clusters = self._create_clusters(X, new_medoids)
new_cost = self._calculate_cost(X, new_clusters, new_medoids)
if new_cost < lowest_cost:
lowest_cost = new_cost
best_medoids = new_medoids
if lowest_cost < cost:
cost = lowest_cost
medoids = best_medoids
else:
break
final_clusters = self._create_clusters(X, medoids)
return self._get_cluster_labels(final_clusters, X)
这是PAM算法的核心实现,包含了完整的构建和交换阶段。算法会持续尝试用非medoids样本替换当前medoids,直到无法通过任何交换进一步降低成本。
PAM算法的优缺点
优点
- 对噪声和异常值鲁棒性强,因为使用实际数据点作为中心
- 适用于任何可以定义距离度量的数据类型
- 结果易于解释,因为聚类中心是实际存在的样本
缺点
- 计算复杂度高,特别是对于大型数据集
- 需要预先指定聚类数量k
- 对初始medoids选择敏感,可能收敛到局部最优解
实际应用建议
- 对于小型到中型数据集(样本数<10,000),PAM是一个不错的选择
- 可以尝试多次运行算法,选择成本最低的结果
- 对于大型数据集,可以考虑使用CLARA或CLARANS等PAM的变种算法
- 结合轮廓系数等指标帮助确定最佳聚类数量k
通过ML-From-Scratch项目中的这个PAM实现,我们可以清晰地理解这一经典聚类算法的工作原理和实现细节,为进一步研究和应用打下坚实基础。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考