机器学习小白一枚,上班的第一周,老板让我去了解以下聚类算法。经过网上的资料与学习,总结了常用的六种聚类算法,包括三种不需要预先指定聚类数目聚类算法和三种需要预先指定聚类数目聚类算法。
不需要预先指定聚类数目聚类算法
1. DBSCAN
1) 基本概念
DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法是一种典型的基于密度的空间聚类算法。和K-Means,BIRCH这些一般只适用于凸样本集的聚类相比,DBSCAN既可以适用于凸样本集,也可以适用于非凸样本集。该算法将具有足够密度的区域划分为簇,并在具有噪声的空间数据库中发现任意形状的簇,它将簇定义为密度相连的点的最大集合。 下面介绍几个概念:
核心点:在它周围的指定半径(ε)内至少有指定数量(MinPts)的点。
密度直达:如果xi
位于xj
的ϵ-
邻域中,且xj
是核心对象,则称xi
由密度直达。注意反之不一定成立,即此时不能说xj由xi密度直达, 除非且xi也是核心对象。
密度可达:对于xi
和xj
,如果存在样本样本序列p1,p2,...,pT,
满足p1=xi,pT=xj
, 且pt+1
由pt
密度直达,则称xj由xi密度可达。也就是说,密度可达满足传递性。此时序列中的传递样本p1,p2,...,pT−1
均为核心对象,因为只有核心对象才能使其他样本密度直达。注意密度可达也不满足对称性,这个可以由密度直达的不对称性得出。
密度相连:对于xi
和xj
,如果存在核心对象样本xk
,使xi
和xj
均由xk
密度可达,则称xi
和xj
密度相连。注意密度相连关系是满足对称性的。
2)DBSCAN的算法步骤
1.选择参数:选择合适的ε和MinPts。
2.标记点:遍历数据集,标记每个点为核心点、边界点或噪声点。
3.判断R里面包含的样本点个数是否大于min_point,如果小于,则为噪声点,标记为已见,如果大于,则P为核心点,创建一个类C,邻域R里面的点都属于类C,如果邻域R内除了P还有其他核心点。则他们邻域里面的点也属于类C,一直迭代,直到核心点邻域里只有它自己为核心点才停止。
4.形成簇:从一个核心点开始,通过密度可达性将所有密度相连的点归为一个簇,重复直到所有点都被访问。
3) 优缺点
优点:
1.可以自动决定类的数量。不需要人为假设。
2.可以发现任意形状的簇类,而不像K-means那样只能发现圆形簇
3.可以识别噪声点,抗噪声能力较强
缺点:
1.不能很好的应用在高维数据中
2. 如果样本集的密度不均匀,效果就不好
4)代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from memory_profiler import profile
import time
from matplotlib.gridspec import GridSpec
@profile
def run_dbscan():
# 记录开始时间
start_time = time.time()
# 生成样本数据
X, labels_true = make_blobs(n_samples=1000, centers=3, cluster_std=0.5, random_state=0)
# 标准化数据
X = StandardScaler().fit_transform(X)
# 使用DBSCAN进行聚类
db = DBSCAN(eps=0.3, min_samples=10).fit(X)
labels = db.labels_
# 记录结束时间并计算耗时
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
# 绘制聚类结果
plt.figure(figsize=(14, 6))
# 创建GridSpec对象
gs = GridSpec(1, 3, width_ratios=[1, 1, 0.05])
# 左侧子图:原始数据
ax1 = plt.subplot(gs[0])
ax1.scatter(X[:, 0], X[:, 1], c='gray', marker='o', edgecolors='k', s=50)
ax1.set_title('Original Data')
ax1.set_xlabel('Feature 1')
ax1.set_ylabel('Feature 2')
# 右侧子图:聚类结果
ax2 = plt.subplot(gs[1])
# 创建噪声点掩码
noise_mask = (labels == -1)
core_mask = (labels != -1)
# 绘制聚类点
scatter = ax2.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
# 绘制噪声点
ax2.scatter(X[noise_mask, 0], X[noise_mask, 1], c='gray', marker='o', edgecolors='k', s=50, label='Noise')
ax2.set_title('DBSCAN Clustering')
ax2.set_xlabel('Feature 1')
ax2.set_ylabel('Feature 2')
# 添加颜色条
cbar_ax = plt.subplot(gs[2])
plt.colorbar(scatter, cax=cbar_ax)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
run_dbscan()
2. Mean Shift
1)基本原理
Mean Shift 算法基于核密度估计(Kernel Density Estimation, KDE)的思想。核密度估计是一种通过对每个数据点周围的数据施加一个核函数的权重来估计数据分布密度的方法。在Mean Shift中,使用的核函数通常是高斯核函数
2)算法步骤
1.初始化
选择一个合适的带宽 h,用于定义核函数的宽度。
对每个数据点 ,初始化一个均值漂移向量 ,通常为零向量。
2.计算均值漂移向量:
对于每个数据点,计算其在带宽 内的均值漂移向量(mean shift vector)。
密度中心的计算公式为:
其中 是以为中心、带宽为 h 的邻域,K是核函数(通常是高斯核函数)。
3.更新数据点位置:
根据计算得到的均值漂移向量,更新数据点的位置:
重复上述步骤直到收敛,即直到均值漂移向量 趋近于零向量或小于阈值。
4.聚类结果
当所有数据点的位置收敛后,可以将数据点分配到最终收敛的位置作为其聚类中心。
可以根据数据点最终的位置和所在的聚类来确定聚类簇。
3)优缺点
优点:
非参数性:Mean Shift 算法不需要预先指定聚类的数量,而是根据数据的密度分布自动确定聚类的数量和形状,因此适用于各种形状和大小的聚类簇。
不需要假设数据分布:与某些聚类方法(如 K-means)需要假设数据满足特定分布形式不同,Mean Shift 算法对数据分布的假设较少,适用于更广泛的数据类型。
全局收敛性:在理论上,Mean Shift 算法可以收敛到全局最优,即找到数据的所有密度最大值(峰值)和聚类中心。
适应性强:对于密度差异较大的数据集,Mean Shift 算法可以较好地识别出密度较高的区域作为聚类中心。
无需标记样本:与一些需要标记样本的监督学习方法不同,Mean Shift 算法是一种无监督学习方法,可以直接应用于无标记数据。
缺点:
对初始点敏感:Mean Shift 算法是基于迭代的算法,最终结果可能依赖于初始点的选择,特别是在数据分布复杂或者密度变化较大的情况下。
不适用于高维稀疏数据:在高维度空间中,由于维度灾难的影响和计算复杂度的增加,Mean Shift 算法可能不适用于处理高维稀疏数据。
不适合处理大量噪声点:对于包含大量噪声点的数据集,Mean Shift 算法可能会产生不合理的聚类结果,因为噪声点可能会影响密度估计和聚类中心的计算。
4) 代码
import numpy as np
from sklearn.cluster import MeanShift
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import time
from memory_profiler import profile
@profile
def run_dbscan():
# 记录开始时间
start_time = time.time()
# 生成样本数据
X, labels_true = make_blobs(n_samples=1000, centers=3, cluster_std=0.5, random_state=0)
# 标准化数据
X = StandardScaler().fit_transform(X)
# 使用MeanShift进行聚类
ms = MeanShift(bin_seeding=True,cluster_all=False,bandwidth=None).fit(X)
labels = ms.labels_
# 记录结束时间并计算耗时
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
# 绘制聚类结果
plt.figure(figsize=(14, 6))
# 创建GridSpec对象
gs = GridSpec(1, 3, width_ratios=[1, 1, 0.05])
# 左侧子图:原始数据
ax1 = plt.subplot(gs[0])
ax1.scatter(X[:, 0], X[:, 1], c='gray', marker='o', edgecolors='k', s=50)
ax1.set_title('Original Data')
ax1.set_xlabel('Feature 1')
ax1.set_ylabel('Feature 2')
# 右侧子图:聚类结果
ax2 = plt.subplot(gs[1])
# 创建噪声点掩码
noise_mask = (labels == -1)
# 绘制聚类点
scatter = ax2.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
# 绘制噪声点
ax2.scatter(X[noise_mask, 0], X[noise_mask, 1], c='gray', marker='o', edgecolors='k', s=50, label='Noise')
ax2.set_title('MeanShift Clustering')
ax2.set_xlabel('Feature 1')
ax2.set_ylabel('Feature 2')
# 添加颜色条
cbar_ax = plt.subplot(gs[2])
plt.colorbar(scatter, cax=cbar_ax)
# 添加图例
ax2.legend(loc='upper right')
plt.tight_layout()
plt.show()
if __name__ == '__main__':
run_dbscan()
3. Affinity Propagation
1)基本原理
亲和力传播(Affinity Propagation,AP)是一种基于实例的学习算法,用于聚类。它通过发送消息在数据点之间建立关系,并选择最佳的聚类结果。基于数据点之间的相似度(或称为亲和力)来确定聚类。
相似度矩阵:相似度矩阵表示每对数据点之间的相似度,常用的相似度度量包括负欧氏距离、相关系数等。相似度越高,数据点越相似。
亲和度(Responsibility):数据点 i认为数据点 k作为其聚类中心的适合程度。
可用度(Availability):数据点 k作为聚类中心对数据点 i 的吸引程度。
亲和度更新:考虑当前数据点作为各可能聚类中心的适合程度,计算公式为:
公式中的 r(i,k)表示数据点 i 与聚类中心 k之间的亲和度。亲和度是衡量数据点与聚类中心之间相似度的指标。
s(i,k)是数据点 i 与聚类中心 k之间的原始亲和度值,这可能是基于数据点之间的距离或其他相似性度量。
这个最大值是针对所有可能的聚类中心 k′计算的,其中 k′从 1 到 K(除了当前的 k),并且 a(i,k′) 是与数据点 i 和聚类中心 k′相关的一个额外的量,可能表示某种形式的权重或调整因子。
这种调整的目的通常是为了避免某个数据点与多个聚类中心的亲和度过高,从而促进聚类的清晰度和分离度。通过从原始亲和度中减去其他聚类中心的最大亲和度(加上额外的量 a(i,k′),可以降低数据点与多个聚类中心的关联度,使得数据点更倾向于属于一个特定的聚类中心。
2)主要步骤
1.计算相似度矩阵:首先,计算数据点之间的相似度矩阵。相似度矩阵通常使用负欧氏距离来表示。这个相似度矩阵表示每对数据点之间的相似度。
2.初始化亲和度和可用度:初始化亲和度(Responsibility)矩阵 r(i,k)和可用度(Availability)矩阵 a(i,k)为零矩阵
3.更新亲和度:数据点 i认为数据点 k 作为其聚类中心的适合程度,是基于当前相似度和排除其他聚类中心的最大值计算的。
4.更新可用度:可用度 a(i,k),计算公式为:
这个公式的意思是:数据点 k 作为聚类中心对数据点 i的吸引程度,是基于当前亲和度和其他数据点对该聚类中心的最大值计算的。
5.重复迭代
反复执行亲和度和可用度的更新步骤,直到算法收敛或达到预定的迭代次数。收敛的标准是亲和度和可用度的变化趋于稳定。
6.确定聚类中心
在算法收敛后,通过计算亲和度和可用度的和 r(i,k)+a(i,k) 来确定每个数据点的聚类中心,选择和最大的聚类中心作为该数据点的代表。
7.分配聚类标签:
根据确定的聚类中心,分配每个数据点的聚类标签,完成聚类过程。
3)优缺点
优点:
1.自动确定聚类数:AP 不需要预先指定聚类的数量。它通过数据点之间的相似度来自动选择聚类中心,这对于实际应用中不知道聚类数的情况非常有用。
2.不需要初始化聚类中心:AP 不像 K-means 等算法那样需要随机初始化聚类中心,这减少了因为初始化不当而导致结果不稳定的情况。
3.处理噪声和异常值:AP 能够有效处理数据中的噪声和异常值,因为它考虑了所有数据点的相似度,并通过迭代过程逐渐确定聚类中心。
4.适用于非球形聚类:AP 可以处理非球形的聚类,因为它依赖于数据点之间的相似度矩阵,而不是假设数据点分布的形状。
缺点:
1.计算复杂度高:AP 需要计算和存储完整的相似度矩阵,计算复杂度为 O(N^2),这使得在处理大规模数据时效率较低。
2.内存消耗大:AP 需要存储 N×N的相似度矩阵,这在数据量很大的情况下会占用大量内存
3.对相似度的选择敏感:AP 的结果对相似度的选择非常敏感。如果相似度矩阵的构建不合理,可能会影响聚类效果。
4.参数调节复杂:AP 有两个主要参数(偏好值和阻尼系数)需要调节,这些参数对聚类结果有很大影响,选择合适的参数值可能需要一些实验。
4) 代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import AffinityPropagation
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from matplotlib.gridspec import GridSpec
from memory_profiler import profile
import time
@profile
def run_dbscan():
# 记录开始时间
start_time = time.time()
# 生成样本数据
X, labels_true = make_blobs(n_samples=1000, centers=3, cluster_std=0.5, random_state=0)
# 标准化数据
X = StandardScaler().fit_transform(X)
# 创建AffinityPropagation模型
ap = AffinityPropagation(damping=0.7, preference=-100, affinity='euclidean', max_iter=200, verbose=True, random_state=0).fit(X)
# 训练模型并预测聚类标签
labels = ap.labels_
# 记录结束时间并计算耗时
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
# 绘制聚类结果
plt.figure(figsize=(14, 6))
# 创建GridSpec对象,设置子图的比例
gs = GridSpec(1, 3, width_ratios=[1, 1, 0.1])
# 左侧子图:原始数据
ax1 = plt.subplot(gs[0])
ax1.scatter(X[:, 0], X[:, 1], c='gray', marker='o', edgecolors='k', s=50)
ax1.set_title('Original Data')
ax1.set_xlabel('Feature 1')
ax1.set_ylabel('Feature 2')
# 右侧子图:聚类结果
ax2 = plt.subplot(gs[1])
scatter = ax2.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
ax2.set_title('Affinity Propagation')
ax2.set_xlabel('Feature 1')
ax2.set_ylabel('Feature 2')
# 添加颜色条
cbar_ax = plt.subplot(gs[2])
plt.colorbar(scatter, cax=cbar_ax)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
run_dbscan()
需要预先指定聚类数目聚类算法
1. K-means
1)基本概念
K-means 算法旨在将数据集中的样本分为 K 个不重叠的簇(cluster)。每个簇通过其质心(centroid)来表示,质心是簇中所有样本点的平均值。
2)算法步骤
1.初始化:首先确定要分成多少个簇,即 K 的值。随机选择 K个样本点作为初始的质心,或者通过其他启发式方法选择初始质心,例如 K-means++ 算法。
2.分配样本到最近的质心:对于每个样本,计算它与所有质心的距离,通常使用欧式距离或其他距离度量。将每个样本分配给距离最近的质心所属的簇。
3.更新质心:对每个簇,计算其所有成员样本的均值,更新质心为该均值。
4.重复迭代:重复迭代直至收敛。当算法收敛时,每个样本被分配到一个簇中,并且簇的质心保持稳定。
3)优缺点
优点:
1.简单和高效:K-means 算法实现简单,易于理解和实现。在大规模数据集上也能有效运行。
2.适用于密集型数据:在处理密集型数据时,K-means 算法表现良好。
3.结果可解释性强:聚类结果相对直观,每个簇的中心点对应于数据的平均值,便于解释和理解。
缺点:
1.需要预先设定簇的数量 K:
2.对异常值和噪声敏感:对于非球形簇形状或不均匀大小的簇效果不佳。
3.难以处理不同密度和大小的簇:K-means 假设所有簇具有相似的方差。
4)代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from matplotlib.gridspec import GridSpec
from memory_profiler import profile
import time
@profile
def run_dbscan():
# 记录开始时间
start_time = time.time()
# 生成样本数据,标准化
X, labels_true = make_blobs(n_samples=1000, centers=3, cluster_std=0.5, random_state=0)
X = StandardScaler().fit_transform(X)
# 定义KMeans模型
k = 3
km= KMeans(n_clusters=k, random_state=0).fit(X)
# 获取聚类结果
labels = km.labels_
# 记录结束时间并计算耗时
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
# 绘制聚类结果
plt.figure(figsize=(14, 6))
# 创建GridSpec对象
gs = GridSpec(1, 3, width_ratios=[1, 1, 0.05])
# 左侧子图:原始数据
ax1 = plt.subplot(gs[0])
ax1.scatter(X[:, 0], X[:, 1], c='gray', marker='o', edgecolors='k', s=50)
ax1.set_title('Original Data')
ax1.set_xlabel('Feature 1')
ax1.set_ylabel('Feature 2')
# 右侧子图:聚类结果
ax2 = plt.subplot(gs[1])
# 创建噪声点掩码
noise_mask = (labels == -1)
core_mask = (labels != -1)
# 绘制聚类点
scatter = ax2.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
# 绘制噪声点
ax2.scatter(X[noise_mask, 0], X[noise_mask, 1], c='gray', marker='o', edgecolors='k', s=50, label='Noise')
ax2.set_title('K-means Clustering')
ax2.set_xlabel('Feature 1')
ax2.set_ylabel('Feature 2')
# 添加颜色条
cbar_ax = plt.subplot(gs[2])
plt.colorbar(scatter, cax=cbar_ax)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
run_dbscan()
2. GMM
1)基本概念
高斯混合模型(Gaussian Mixture Model, GMM)是一种概率模型,用于表示具有多个高斯分布的子群体的分布情况。GMM在聚类分析中是一种灵活且强大的工具,可以处理数据的复杂结构,尤其是当数据来自多个高斯分布时。相比于K-means算法,GMM具有更高的表达能力,因为它考虑了数据的概率分布。
1.高斯分布:每个子群体的数据点都服从一个高斯分布(也称正态分布)。
2.混合模型:整个数据集是由多个高斯分布的线性组合而成,每个高斯分布代表一个簇。
3.参数:
均值向量(mean vector):表示每个高斯分布的中心。
协方差矩阵(covariance matrix):描述高斯分布的形状和方向。
混合系数(mixing coefficient):表示每个高斯分布的权重。
2)算法步骤
1.初始化:选择组件数 K,预先确定模型中高斯分布的数量。包括每个高斯分布的均值 (μ)、协方差矩阵 (Σ) 和混合系数 (π)。这些参数可以随机初始化或使用其他方法(如 K-means)进行初始化。
2. E步(期望步):计算每个数据点属于每个高斯分布的概率(即责任值,Responsibility)。具体公式为:
3. M步(最大化步):使用 E 步骤计算出的责任值来更新模型参数,使对数似然函数达到最大。
4. 计算对数似然函数:计算当前参数下的对数似然函数,判断是否收敛。如果对数似然函数的增量小于设定的阈值或达到最大迭代次数,则认为算法收敛。
5.重复 E 步骤和 M 步骤:直到对数似然函数收敛。
3)优缺点
优点:
1.柔性聚类:GMM 是一种软聚类算法,它为每个数据点分配属于每个簇的概率。这种柔性聚类方法能够更好地处理边界模糊的数据点。
2.处理不同形状和大小的簇:个簇由一个高斯分布描述,可以有不同的均值和协方差矩阵。因此,GMM 能够适应数据中复杂的簇结构。
缺点:
1.易受异常值影响:GMM 可能会受到异常值的影响,因为异常值可能会显著改变高斯分布的参数估计,从而影响聚类结果
2.难以确定簇数:GMM 需要预先指定簇的数量 K,这在实际应用中可能是一个挑战。选择不当的 K 值可能导致次优的聚类结果
3.假设簇为高斯分布:GMM 假设每个簇都符合高斯分布,但在实际应用中,数据的分布可能并不总是高斯分布。当数据的实际分布与高斯分布差异较大时,GMM 的性能可能受到影响。
4)代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.mixture import GaussianMixture
from sklearn.preprocessing import StandardScaler
from matplotlib.gridspec import GridSpec
from memory_profiler import profile
import time
@profile
def run_dbscan():
# 记录开始时间
start_time = time.time()
# 生成样本数据
X, labels_true = make_blobs(n_samples=1000, centers=3, cluster_std=0.5, random_state=0)
# 标准化数据
X = StandardScaler().fit_transform(X)
# 定义GaussianMixture模型
gmm = GaussianMixture(n_components=3, random_state=0).fit(X)
labels = gmm.predict(X)
# 记录结束时间并计算耗时
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
# 绘制聚类结果
plt.figure(figsize=(14, 6))
# 创建GridSpec对象,设置子图的比例
gs = GridSpec(1, 3, width_ratios=[1, 1, 0.1])
# 左侧子图:原始数据
ax1 = plt.subplot(gs[0])
ax1.scatter(X[:, 0], X[:, 1], c='gray', marker='o', edgecolors='k', s=50)
ax1.set_title('Original Data')
ax1.set_xlabel('Feature 1')
ax1.set_ylabel('Feature 2')
# 右侧子图:聚类结果
ax2 = plt.subplot(gs[1])
scatter = ax2.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
ax2.set_title('Affinity Propagation')
ax2.set_xlabel('Feature 1')
ax2.set_ylabel('Feature 2')
# 添加颜色条
cbar_ax = plt.subplot(gs[2])
plt.colorbar(scatter, cax=cbar_ax)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
run_dbscan()
3.谱聚类
1)基本概念
谱聚类(Spectral Clustering)是一种基于图论的聚类算法,适用于非凸形状的数据集。它利用数据的谱信息(即数据点之间的相似度矩阵的特征值和特征向量)进行聚类。
2)算法步骤
1.构建相似度矩阵:计算数据点之间的相似度矩阵 S
2.构建拉普拉斯矩阵:根据相似度矩阵 S,构建图的拉普拉斯矩阵 L
3.特征分解:对拉普拉斯矩阵 L进行特征分解,得到前 k个特征向量,组成特征矩阵 U。
4.聚类:对特征矩阵 U 的行进行标准化处理,每行表示一个数据点在新的特征空间中的位置。使用K-means或其他聚类算法对这些行进行聚类,得到最终的簇划分。
3)优缺点
优点:
1.处理复杂形状的簇:能够识别和处理任意形状和非凸形状的簇。
2.高维数据适用:在高维数据上表现良好,能够有效处理高维数据集。
3.全局优化:通过全局信息(相似性矩阵)进行优化,避免局部最优问题。
缺点:
1.计算复杂度高:谱聚类的计算复杂度较高,特别是在处理大规模数据时,计算量较大。
2.需要预先确定参数:如何选择合适的相似性度量、邻近参数等关键参数对聚类结果影响较大,需要先验知识或者调参。
3.对于非均匀分布的数据效果不佳:在处理非均匀分布的数据时,可能会导致聚类效果不理想。
4)代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import SpectralClustering
from sklearn.datasets import make_blobs
from matplotlib.gridspec import GridSpec
from sklearn.preprocessing import StandardScaler
from memory_profiler import profile
import time
@profile
def run_dbscan():
# 记录开始时间
start_time = time.time()
# 生成样本数据
X, labels_true = make_blobs(n_samples=1000, centers=3, cluster_std=0.5, random_state=0)
# 标准化数据
X = StandardScaler().fit_transform(X)
# 创建SpectralClustering模型
spectral = SpectralClustering(n_clusters=3, affinity='rbf', random_state=0)
# 训练模型并预测聚类标签
labels = spectral.fit_predict(X)
# 记录结束时间并计算耗时
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
# 绘制聚类结果
plt.figure(figsize=(14, 6))
# 创建GridSpec对象,设置子图的比例
gs = GridSpec(1, 3, width_ratios=[1, 1, 0.1])
# 左侧子图:原始数据
ax1 = plt.subplot(gs[0])
ax1.scatter(X[:, 0], X[:, 1], c='gray', marker='o', edgecolors='k', s=50)
ax1.set_title('Original Data')
ax1.set_xlabel('Feature 1')
ax1.set_ylabel('Feature 2')
# 右侧子图:聚类结果
ax2 = plt.subplot(gs[1])
scatter = ax2.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
ax2.set_title('Affinity Propagation')
ax2.set_xlabel('Feature 1')
ax2.set_ylabel('Feature 2')
# 添加颜色条
cbar_ax = plt.subplot(gs[2])
plt.colorbar(scatter, cax=cbar_ax)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
run_dbscan()