一、原理
K-medoids算法是一种聚类算法,它的原理与K-Means算法相似,但关键区别在于它使用数据集中的实际点(称为medoids)作为簇的中心点,而不是像K-Means那样使用簇内所有点的平均值。以下是K-medoids算法的主要原理:
1. 初始化
选择初始Medoids:首先,从数据集中随机选择K个数据点作为初始的medoids,这些medoids将作为初始的簇中心点。
2. 分配数据点到簇
计算距离:对于数据集中的每个非medoid点,计算它到所有K个medoids的距离。
分配簇:根据计算得到的距离,将每个非medoid点分配到离它最近的medoid所在的簇中。
3. 更新簇中心点
选择新的Medoids:在每个簇中,尝试用簇内的其他非medoid点替换当前的medoid。替换的标准是使得替换后簇内所有点到新medoid的总距离(或称为代价)最小化。
接受或拒绝替换:如果替换某个medoid后,簇的总距离减小了,则接受这个替换;否则,保持原来的medoid不变。
4. 迭代
重复分配和更新:重复上述的分配和更新步骤,直到medoids不再发生变化,或者达到预设的最大迭代次数。
5. 输出结果
最终簇和Medoids:当算法收敛时,输出最终的K个簇以及每个簇的medoid。
优点
鲁棒性:由于medoids是数据集中的实际点,K-medoids算法对噪声和离群点具有更好的鲁棒性。
可解释性:每个簇的medoid可以直接观察和分析,使得聚类结果更容易解释。
缺点
计算复杂度:与K-Means算法相比,K-medoids算法的计算复杂度更高,因为每次迭代都需要在每个簇中选择一个新的medoid,这通常涉及大量的距离计算。
敏感性:K-medoids算法的性能也受到初始medoids选择的影响,不同的初始选择可能导致不同的聚类结果。
应用
K-medoids算法广泛应用于各种领域的数据聚类分析中,特别是在需要处理噪声和离群点的情况下。在Python中,可以使用scikit-learn库中的KMedoids类来实现K-medoids算法。
总之,K-medoids算法通过选择数据集中的实际点作为簇的中心点,并在迭代过程中不断优化这些中心点,从而实现了对数据的有效聚类。
二、Python实践
K-medoids算法的Python实现可以通过自定义函数来完成,但请注意,scikit-learn库本身并不直接提供K-medoids的实现(尽管它提供了K-Means和其他聚类算法)。不过,我们可以利用sklearn.cluster中的KMedoids类(注意:在较新版本的scikit-learn中,这个类可能不是内置的,但可以通过sklearn.cluster.k_medoids_函数访问,或者你可以使用第三方库如pyclustering)。
然而,为了演示目的,我将提供一个简单的K-medoids算法的Python实现。这个实现将包括初始化、分配数据点到簇、以及更新簇中心(medoids)的基本步骤。
请注意,这个实现可能不是最优的,特别是在处理大数据集时,因为它在每次迭代中都会计算所有数据点到所有候选medoids的距离。
import numpy as np
def find_closest(points, medoid):
"""找到离给定medoid最近的点"""
distances = np.sqrt(((points - medoid)**2).sum(axis=1))
return np.argmin(distances)
def k_medoids(X, k, max_iter=100):
"""
K-medoids聚类算法的实现。
参数:
- X: ndarray, 形状为 (n_samples, n_features),数据点集合。
- k: int, 要形成的簇的数量。
- max_iter: int, 最大迭代次数。
返回:
- medoids: ndarray, 形状为 (k, n_features),每个簇的medoid。
- labels: ndarray, 形状为 (n_samples,), 每个点的簇标签。
"""
n_samples, n_features = X.shape
# 初始化medoids
medoid_indices = np.random.choice(n_samples, k, replace=False)
medoids = X[medoid_indices]
# 迭代开始
for _ in range(max_iter):
# 分配簇
clusters = [[] for _ in range(k)]
for i in range(n_samples):
distances = np.sqrt(((X[i] - medoids)**2).sum(axis=1))
closest_medoid_index = np.argmin(distances)
clusters[closest_medoid_index].append(i)
# 尝试更新medoids
new_medoids = np.copy(medoids)
for j in range(k):
if len(clusters[j]) > 0:
cluster_points = X[clusters[j]]
new_medoid_index = find_closest(cluster_points, new_medoids[j])
new_medoids[j] = cluster_points[new_medoid_index]
# 检查是否收敛
if np.array_equal(new_medoids, medoids):
break
medoids = new_medoids
# 为每个点分配簇标签
labels = np.zeros(n_samples, dtype=int)
for j in range(k):
for point in clusters[j]:
labels[point] = j
return medoids, labels
# 示例用法
if __name__ == "__main__":
np.random.seed(0)
X = np.random.randn(100, 2) # 生成一些随机数据
k = 3 # 聚类数量
medoids, labels = k_medoids(X, k)
print("Medoids:\n", medoids)
print("Labels:", labels)
# 可选:使用matplotlib进行可视化
import matplotlib.pyplot as plt
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', marker='o', edgecolor='k')
plt.scatter(medoids[:, 0], medoids[:, 1], s=200, c='red', marker='X')
plt.title('K-Medoids Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.colorbar(label='Cluster')
plt.show()
在这个实现中,find_closest函数用于在给定簇内找到离当前medoid最近的点。k_medoids函数执行K-medoids算法的主要步骤,包括初始化medoids、分配簇、更新medoids以及迭代直到收敛或达到最大迭代次数。最后,我们使用matplotlib(如果已安装)来可视化聚类结果。