K-Mediods算法

K-Mediods算法

1. 实验目标

学习并使用 k k k- m e d o i d s medoids medoids算法,了解该算法的优缺点

2. 实验主要使用的 P y t h o n Python Python

名称版本简介
N u m p y Numpy Numpy 1.16.0 1.16.0 1.16.0线性代数
P a n d a s Pandas Pandas 0.25.0 0.25.0 0.25.0数据分析
M a t p l o t l i b Matplotlib Matplotlib 3.1.0 3.1.0 3.1.0数据可视化
S K l e a r n SKlearn SKlearn 0.22.1 0.22.1 0.22.1机器学习

3. 实验步骤

步骤1 安装并导入所需要的库

!pip install numpy==1.16.0
!pip install pandas==0.25.0
!pip install scikit-learn==0.22.1
!pip install matplotlib==3.1.0
!pip install treelib
!pip install pyclust

from sklearn.datasets import make_blobs
from matplotlib import pyplot
import numpy as np
import random

步骤2 定义一个k-medoid类

定义一个k-medoid类,__init__方法定义参数

2.1 创建测试数据并画图显示

scikit中的make_blobs方法常被用来生成聚类算法的测试数据,直观地说,make_blobs会根据用户指定的特征数量、中心点数量、范围等来生成几类数据,这些数据可用于测试聚类算法的效果。

  • @ param n_samples : 表示多少个点,
  • @ param n_features : 表示几维
  • @ param centers : 得到的data是n个点各自坐标
  • @ param target : 每个坐标的分类(若我规定好四个分类,target长度为n范围为0-3,主要是画图颜色区别)
2.2 定义欧式距离的计算
2.3 K-mediods算法
  • @ param func_of_dis :距离公式
2.4 画图分类比较

获取数据并画图展示开始未分类的图,展示分类后的图。

代码:

class KMediod():
    def __init__(self, n_points, k_num_center):
        self.n_points = n_points
        self.k_num_center = k_num_center
        self.data = None
    def get_test_data(self):
        self.data, target = make_blobs(n_samples=self.n_points, n_features=2, centers=self.n_points)
        np.put(self.data, [self.n_points, 0], 500, mode='clip')
        np.put(self.data, [self.n_points, 1], 500, mode='clip')
        pyplot.scatter(self.data[:, 0], self.data[:, 1], c=target)
    # 画图
        pyplot.show()
    def ou_distance(self,x, y):
        return np.sqrt(sum(np.square(x - y)))
    def run_k_center(self,func_of_dis):
        print('初始化', self.k_num_center, '个中心点')
        indexs = list(range(len(self.data)))
        random.shuffle(indexs)         # 随机选择质心
        init_centroids_index = indexs[:self.k_num_center]
        centroids = self.data[init_centroids_index, :]      # 初始中心点
        
        levels = list(range(self.k_num_center))  # 确定种类编号
        print('开始迭代')
        sample_target = []
        if_stop = False     # 用来判断聚类是否已经收敛
        while(not if_stop):
            if_stop = True
            classify_points = [[centroid] for centroid in centroids]
            sample_target = []
        
            # 遍历数据
            for sample in self.data:
                # 计算距离,由距离该数据最近的核心,确定该点所属类别
                distances = [func_of_dis(sample, centroid) for centroid in centroids] 
                cur_level = np.argmin(distances)
                sample_target.append(cur_level)   
                classify_points[cur_level].append(sample) # 统计,方便迭代完成后重新计算中间点

            # 重新划分质心
            for i in range(self.k_num_center):       # 几类中分别寻找一个最优点
                distances = [func_of_dis(point_1, centroids[i]) for point_1 in classify_points[i]]
                now_distances = sum(distances)       # 首先计算出现在中心点和其他所有点的距离总和
                for point in classify_points[i]:
                    distances = [func_of_dis(point_1, point) for point_1 in classify_points[i]]
                    new_distance = sum(distances)

                    # 计算出该聚簇中各个点与其他所有点的总和,若是有小于当前中心点的距离总和的,中心点去掉
                    if new_distance < now_distances:
                        now_distances = new_distance
                        centroids[i] = point    # 换成该点
                        if_stop = False
        print('结束')
        return sample_target
    def run(self):
        self.get_test_data()
        predict = self.run_k_center(self.ou_distance)
        pyplot.scatter(self.data[:, 0], self.data[:, 1], c=predict)
        pyplot.show()

test=KMediod(n_points=1000, k_num_center=3)
test.run()

在构造初始点的时候,自己定义加入了几个孤立点

一开始的所有点:(可以看出其他点是混在一起有许多分类的)
分类后的图:

步骤3 sklearn实现K-Medoids算法

3.1 引入所需要的库
from pyclust import KMedoids
import numpy as np
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
3.2构造示例数据集(加入少量脏数据)
data1 = np.random.normal(0,0.9,(1000,10))
data2 = np.random.normal(1,0.9,(1000,10))
data3 = np.random.normal(2,0.9,(1000,10))
data4 = np.random.normal(3,0.9,(1000,10))
data5 = np.random.normal(50,0.9,(50,10))
data = np.concatenate((data1,data2,data3,data4,data5))
3.3 准备可视化需要的降维数据
data_TSNE = TSNE(learning_rate=100).fit_transform(data)
3.4 对不同的k进行试探性K-medoids聚类并可视化
plt.figure(figsize=(12,8))
for i in range(2,6):
    k = KMedoids(n_clusters=i,distance='euclidean',max_iter=1000).fit_predict(data)
    colors = ([['red','blue','black','yellow','green'][i] for i in k])
    plt.subplot(219+i)
    plt.scatter(data_TSNE[:,0],data_TSNE[:,1],c=colors,s=10)
    plt.title('K-medoids Resul of '.format(str(i)))
### 回答1: k-medoids算法是一种聚类算法,它是k-means算法的一种改进。k-medoids算法的主要思想是选择k个代表性样本作为聚类中心,然后将每个样本分配到最近的聚类中心中。与k-means算法不同的是,k-medoids算法使用代表性样本作为聚类中心,而不是使用样本的平均值作为聚类中心。 以下是使用Python实现k-medoids算法的代码: ```python import numpy as np from sklearn.metrics.pairwise import pairwise_distances def k_medoids(X, k, max_iter=100): # 初始化聚类中心 centers = np.random.choice(len(X), k, replace=False) # 迭代更新聚类中心 for i in range(max_iter): # 计算每个样本到聚类中心的距离 distances = pairwise_distances(X, X[centers]) # 找到每个样本距离最近的聚类中心 labels = np.argmin(distances, axis=1) # 更新聚类中心 for j in range(k): # 找到属于第j个聚类的样本 indices = np.where(labels == j)[0] # 计算这些样本与其他样本的距离之和 total_distance = np.sum(pairwise_distances(X[indices], X[indices])) # 找到距离最小的样本作为新的聚类中心 min_distance = np.inf min_index = centers[j] for index in indices: distance = np.sum(pairwise_distances(X[index].reshape(1, -1), X[indices])) if distance < min_distance: min_distance = distance min_index = index centers[j] = min_index # 返回聚类结果和聚类中心 distances = pairwise_distances(X, X[centers]) labels = np.argmin(distances, axis=1) return labels, centers ``` 该代码使用numpy和sklearn库实现了k-medoids算法。其中,X是样本数据,k是聚类数,max_iter是最大迭代次数。该算法首先随机选择k个样本作为聚类中心,然后迭代更新聚类中心,直到达到最大迭代次数或聚类中心不再改变。在更新聚类中心时,该算法首先计算每个样本到聚类中心的距离,然后找到每个样本距离最近的聚类中心,最后找到距离最小的样本作为新的聚类中心。最终,该算法返回聚类结果和聚类中心。 ### 回答2: k-medoids算法(又称为PAM算法)是聚类算法中的一种。相比于k-means算法,k-medoids更加健壮,能够处理噪声和离群值。k-medoids算法的核心思想就是在k个点中选出一个点作为中心点(即medoid),将其他点分配到距离它们最近的中心点,最终达到聚类的效果。 下面是用Python实现k-medoids算法的代码: ```python import numpy as np from sklearn.metrics.pairwise import pairwise_distances class KMedoids: def __init__(self, k=3, max_iterations=100): self.k = k self.max_iterations = max_iterations def fit(self, X): n_samples, n_features = X.shape # Initialize medoids = np.zeros(self.k, dtype=int) dists = pairwise_distances(X, metric='euclidean') np.fill_diagonal(dists, 0) # Randomly select medoids medoids = np.random.choice(n_samples, self.k, replace=False) # Assign samples to closest medoids labels = np.argmin(dists[medoids], axis=0) for i in range(self.max_iterations): # Update medoids for j in range(self.k): indices = np.where(labels == j)[0] costs = dists[indices, :][:, indices] total_cost = np.sum(costs, axis=1) new_medoid = indices[np.argmin(total_cost)] medoids[j] = new_medoid # Assign samples to closest medoids labels = np.argmin(dists[medoids], axis=0) centroids = X[medoids] return medoids, centroids, labels ``` 这段代码使用了NumPy库和scikit-learn的pairwise_distances函数。输入数据是一个n_samples×n_features的矩阵X,其中n_samples表示样本数,n_features表示特征数。k是聚类的簇数,max_iterations是迭代次数。 首先,将样本两两之间的距离计算出来,并且将对角线上的值设为0。接着,随机选择k个点作为medoids。然后按照距离最近的原则,将其他点分配到距离它们最近的medoids。之后,重复以下步骤: 1. 计算每个簇内距离的总和,将最小的距离和对应的点作为新的medoid。 2. 按照距离最近的原则,将其他点分配到距离它们最近的medoids。 最终返回medoids,centroids和labels,其中medoids表示每个簇的medoid的索引,centroids表示每个簇的中心点,labels表示每个样本所属的簇的索引。 ### 回答3: k-medoids算法是一种常用的聚类算法,与k-means算法相比,它使用代表点(medoids)代替了质心作为聚类中心,因此更具有稳健性。 以下是使用Python实现的k-medoids算法的代码。 1. 导入必要的库 ``` import numpy as np from sklearn.metrics.pairwise import pairwise_distances ``` 2. 定义k-medoids函数 ``` def kmedoids(D, k, max_iter=100): # 随机初始化k个medoids M = list(range(D.shape[0])) np.random.shuffle(M) M = np.array(M[:k]) M_old = np.copy(M) # 迭代k-medoids算法 for _ in range(max_iter): # 计算每个点到medoid的距离 D_M = pairwise_distances(D, D[M]) # 选择最近的medoid作为每个点的cluster labels = np.argmin(D_M, axis=1) # 更新每个cluster的medoid for i in range(k): M[i] = np.median(np.where(labels == i)[0]) # 如果medoids没有改变,则收敛 if np.all(M == M_old): break M_old = np.copy(M) # 返回聚类结果 return labels, M ``` 此函数接受一个距离矩阵D、聚类个数k和最大迭代次数max_iter作为输入。它首先随机选取k个点作为medoids,然后为每个点找到最近的medoid,并将它们分配到相应的cluster中。接下来,它更新每个cluster的medoid,直到收敛为止。最后,它返回每个点所属的cluster和最终的medoids。 3. 示例应用 为了演示如何使用该k-medoids函数,下面通过一个简单的示例来说明。 假设有10个样本,每个样本有3个特征: ``` X = np.random.rand(10, 3) ``` 现在我们想使用k-medoids算法将这些点划分成3个cluster: ``` labels, M = kmedoids(D=pairwise_distances(X), k=3) ``` 其中,D是每个点之间的距离矩阵,由`pairwise_distances`函数计算得出。最终的聚类结果存储在`labels`变量中,medoids存储在`M`变量中。 我们可以将聚类结果可视化: ``` import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure() ax = fig.add_subplot(111, projection='3d') colors = ['r', 'g', 'b'] for i in range(3): idx = np.where(labels == i)[0] ax.scatter(X[idx, 0], X[idx, 1], X[idx, 2], c=colors[i], marker='o') ax.scatter(X[M, 0], X[M, 1], X[M, 2], c='black', marker='x', s=100) ``` 此代码将结果可视化为一个三维散点图,每个cluster用不同的颜色表示,medoids用黑色的X表示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值