【机器学习-无监督学习】k均值聚类

news2024/12/23 6:54:40

在这里插入图片描述

【作者主页】Francek Chen
【专栏介绍】 ⌈ ⌈ Python机器学习 ⌋ ⌋ 机器学习是一门人工智能的分支学科,通过算法和模型让计算机从数据中学习,进行模型训练和优化,做出预测、分类和决策支持。Python成为机器学习的首选语言,依赖于强大的开源库如Scikit-learn、TensorFlow和PyTorch。本专栏介绍机器学习的相关算法以及基于Python的算法实现。
【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/Python_machine_learning。

文章目录

    • 一、k均值聚类的原理
    • 二、动手实现k均值算法
    • 三、k-means++算法
    • 四、Sklearn中的k-means算法
    • 五、拓展:Sklearn中的层次聚类和密度聚类
      • (一)层次聚类
      • (二)密度聚类之DBSCAN算法


  本文开始我们讲解无监督学习算法。在之前的文章中,我们给模型的任务通常是找到样本 x \boldsymbol x x与标签 y y y之间的对应关系。在训练时,模型对样本 x \boldsymbol x x给出预测 y ^ \hat y y^,再通过损失函数计算 y ^ \hat y y^ y y y之间的偏差,从而优化模型。在这一过程中,真实标签 y y y保证我们可以根据模型的预测 y ^ \hat y y^来调整模型,起到了“监督”模型输出的作用。因此,这样的学习过程称为监督学习(supervised learning)。还有一类任务中,我们只有样本 x \boldsymbol x x,却没有其标签 y y y。这类任务也不再是通过 x \boldsymbol x x去预测 y y y,而是通过样本的特征找到样本之间的关联。由于没有标签作为监督信号,这一过程被称为无监督学习(unsupervised learning)。监督学习和无监督学习在某些情况下可以互相转化。例如在卷积神经网络一文中,我们通过训练集中的图像与其类别得到模型,在测试集上完成了图像分类任务,这是有监督学习的过程。我们最后给图像分类的依据是由模型提取出的图像的特征。然而,即使我们一开始就不知道图像的真实类别,也可以通过图像特征之间的相似程度判断出来哪些图像属于同一类。也就是说,我们可以在仅有图像的情况下把猫和狗的图像分为两类,而类别无非是告诉我们这两类分别叫“猫”和“狗”而已。

  本文我们将要讲解的k均值(k-means)聚类算法就是一个无监督学习算法。它的目标是将数据集中的样本根据其特征分为几个类,使得每一类内部样本的特征都尽可能相近,这样的任务通常称为聚类任务。作为最简单的聚类算法,k均值算法在现实中有广泛的应用。下面,我们就来详细讲解k均值算法的原理,然后动手实现该算法,最后我们将介绍改进的k-means++算法。

一、k均值聚类的原理

  假设空间中有一些点,聚类问题的目标就是将这些点按距离分成数类。设数据集 D = { x 1 , ⋯   , x M } \mathcal D=\{\boldsymbol x_1,\cdots,\boldsymbol x_M\} D={x1,,xM},其中每个样本 x i ∈ R n \boldsymbol x_i\in \mathbb R^n xiRn 的特征维数都是 n n n。最终聚簇的个数 K K K由我们提前指定。直观上来说,同一类的点之间距离应该比不同类的点之间的距离远。但是,由于我们没有任何点的真实标签,所以也无法在最开始确定每一类的中心(centroid),以其为基准计算距离并分类。针对这一问题,k均值算法提出了一个非常简单的解决方案:在初始时,随机选取数据集中的 K K K个样本 μ 1 , ⋯   , μ K \boldsymbol\mu_1,\cdots,\boldsymbol\mu_K μ1,,μK,将 μ i \boldsymbol\mu_i μi作为第 i i i类的中心。选取中心后,我们用最简单的方式,把数据集中的点归到最近的中心点所代表的类中。记第 i i i类包含样本的集合为 C i \mathcal C_i Ci,两点之间的距离函数为 d d d,那么 C i \mathcal C_i Ci可以写为 C i = { x j ∈ D ∣ ∀ l ≠ i , d ( x j , μ i ) ≤ d ( x j , μ l ) } \mathcal C_i=\{\boldsymbol x_j\in\mathcal D|\forall l\ne i,d(\boldsymbol x_j,\boldsymbol\mu_i)\le d(\boldsymbol x_j,\boldsymbol\mu_l)\} Ci={xjD∣∀l=i,d(xj,μi)d(xj,μl)}

  当然,仅仅随机选取中心点还不够,我们还要继续进行优化,尽可能减小类内的点到中心点距离。将数据集中所有点到其对应中心距离之和作为损失函数,得到 L ( C 1 , ⋯   , C K ) = ∑ i = 1 K ∑ x ∈ C i d ( x , μ i ) = ∑ i = 1 K ∑ j = 1 M I ( x j ∈ C i ) d ( x j , μ i ) \mathcal L(\mathcal C_1,\cdots,\mathcal C_K)=\sum_{i=1}^K\sum_{\boldsymbol x\in\mathcal C_i}d(\boldsymbol x,\boldsymbol\mu_i)=\sum_{i=1}^K\sum_{j=1}^M\mathbb I(\boldsymbol x_j\in\mathcal C_i)d(\boldsymbol x_j,\boldsymbol\mu_i) L(C1,,CK)=i=1KxCid(x,μi)=i=1Kj=1MI(xjCi)d(xj,μi)

  既然在初始时,各个类的中心点 μ i \boldsymbol\mu_i μi是随机选取的,那么我们应当再选取新的中心点,使得损失函数的值最小。将上式对 μ i \boldsymbol\mu_i μi求偏导,得 ∂ L ∂ μ i = ∑ x ∈ C i ∂ d ( x , μ i ) ∂ μ i \frac{\partial\mathcal L}{\partial\boldsymbol\mu_i}=\sum_{\boldsymbol x\in\mathcal C_i}\frac{\partial d(\boldsymbol x,\boldsymbol\mu_i)}{\partial\boldsymbol\mu_i} μiL=xCiμid(x,μi)

  如果我们用欧氏距离的平方作为度量标准,即 d ( x , μ ) = ∥ x − μ ∥ 2 d(\boldsymbol x,\boldsymbol\mu)=\Vert\boldsymbol x-\boldsymbol\mu\Vert^2 d(x,μ)=xμ2,上式可以进一步计算为 ∂ L ∂ μ i = ∑ x ∈ C i ∂ ∥ x − μ i ∥ 2 ∂ μ i = 2 ∑ x ∈ C i ( x − μ i ) = 2 ∑ x ∈ C i x − 2 ∣ C i ∣ μ i \frac{\partial\mathcal L}{\partial\boldsymbol\mu_i}=\sum_{\boldsymbol x\in\mathcal C_i}\frac{\partial\Vert\boldsymbol x-\boldsymbol\mu_i\Vert^2}{\partial\boldsymbol\mu_i}=2\sum_{\boldsymbol x\in\mathcal C_i}(\boldsymbol x-\boldsymbol\mu_i)=2\sum_{\boldsymbol x\in\mathcal C_i}\boldsymbol x-2|\mathcal C_i|\boldsymbol\mu_i μiL=xCiμixμi2=2xCi(xμi)=2xCix2∣Ciμi

  令该偏导数为零,就得到最优的中心点为: μ i = 1 ∣ C i ∣ ∑ x ∈ C i x \boldsymbol\mu_i=\frac{1}{|\mathcal C_i|}\sum_{\boldsymbol x\in\mathcal C_i}\boldsymbol x μi=Ci1xCix

  上式表明,最优中心点就是 C i \mathcal C_i Ci中所有点的质心。但是,当中心点更新后,每个样本距离最近的中心点可能也会发生变化。因此,我们重新计算每个样本点到中心点的距离,对它们重新分类,再计算新的质心。如此反复迭代,直到各个点的分类几乎不再变化或者达到预设的迭代次数位置。需要注意,如果采用其他的距离函数作为度量,那么最优的中心点就不再是集合的质心。

二、动手实现k均值算法

  下面,我们用一个简单的平面点集kmeans_data.csv来展示k均值聚类算法的效果。首先,我们加载数据集并可视化。数据集中每行包含两个值 x 1 x_1 x1 x 2 x_2 x2,表示平面上坐标为 ( x 1 , x 2 ) (x_1,x_2) (x1,x2)的点。考虑到我们还希望绘制迭代的中间步骤,这里将绘图部分写成一个函数。

import numpy as np
import matplotlib.pyplot as plt

dataset = np.loadtxt('kmeans_data.csv', delimiter=',')
print('数据集大小:', len(dataset))

在这里插入图片描述

# 绘图函数
def show_cluster(dataset, cluster, centroids=None):  
    # dataset:数据
    # centroids:聚类中心点的坐标
    # cluster:每个样本所属聚类
    # 不同种类的颜色,用以区分划分的数据的类别
    colors = ['blue', 'red', 'green', 'purple']
    markers = ['o', '^', 's', 'd']
    # 画出所有样例
    K = len(np.unique(cluster))
    for i in range(K):
        plt.scatter(dataset[cluster == i, 0], dataset[cluster == i, 1], color=colors[i], marker=markers[i])

    # 画出中心点
    if centroids is not None:
        plt.scatter(centroids[:, 0], centroids[:, 1], 
            color=colors[:K], marker='+', s=150)  
        
    plt.show()

# 初始时不区分类别
show_cluster(dataset, np.zeros(len(dataset), dtype=int))

在这里插入图片描述

  对于简单的k均值算法,初始的中心点是从现有样本中随机选取的,我们将其实现如下。

def random_init(dataset, K):
    # 随机选取是不重复的
    idx = np.random.choice(np.arange(len(dataset)), size=K, replace=False)
    return dataset[idx]

  接下来,我们用欧氏距离作为标准,实现上面描述的迭代过程。由于数据集比较简单,我们将迭代的终止条件设置为所有点的分类都不再变化。对于更复杂的数据集,这一条件很可能无法使迭代终止,从而需要我们控制最大迭代次数,或者设置允许类别变动的点的比例等等。

def Kmeans(dataset, K, init_cent):
    # dataset:数据集
    # K:目标聚类数
    # init_cent:初始化中心点的函数
    centroids = init_cent(dataset, K)
    cluster = np.zeros(len(dataset), dtype=int)
    changed = True
    # 开始迭代
    itr = 0
    while changed:
        changed = False
        loss = 0
        for i, data in enumerate(dataset):
            # 寻找最近的中心点
            dis = np.sum((centroids - data) ** 2, axis=-1)
            k = np.argmin(dis)
            # 更新当前样本所属的聚类
            if cluster[i] != k:
                cluster[i] = k
                changed = True
            # 计算损失函数
            loss += np.sum((data - centroids[k]) ** 2)
        # 绘图
        print(f'Iteration {itr}, Loss {loss:.3f}')
        show_cluster(dataset, cluster, centroids)
        # 更新中心点
        for i in range(K):
            centroids[i] = np.mean(dataset[cluster == i], axis=0)
        itr += 1

    return centroids, cluster

  最后,我们观察k均值算法在上面的数据集上聚类的过程。根据上面的可视化结果,我们大概可以看出有4个聚类,因此设定 K = 4 K=4 K=4

np.random.seed(0)
cent, cluster = Kmeans(dataset, 4, random_init)

在这里插入图片描述

三、k-means++算法

  上面的分类结果与我们的主观感受区别不大。但是,k均值算法对初始选择的聚类中心非常敏感,且极易收敛到局部最小值,因此不同的中心选择可能导致完全不同的划分。通常来说,我们可以用不同的随机种子选择多组初值,最终挑出划分最好的那一个。但是,当聚类个数和数据量较大时,k均值算法运行需要的时间很长,反复调整随机种子也很不方便。因此,改进的k均值算法——k-means++算法提出了一种新的初始中心选择方法,使算法整体对随机种子的依赖大大减小。

  首先,k-means++算法从所有样本中随机选取一个点当作第一个聚类的中心点。直观上来讲,我们希望初始的中心点尽可能散开。因此在选择接下来的中心点时,该算法会将样本到当前中心点的距离也纳入考量。设目前已有 k k k个中心点,分别是 μ 1 , ⋯   , μ k \boldsymbol\mu_1,\cdots,\boldsymbol\mu_k μ1,,μk,对于样本 x \boldsymbol x x,其他与最近的中心点的距离为 D ( x ) D(\boldsymbol x) D(x)。为了使各个中心点之间的距离尽可能大,令 x \boldsymbol x x被选为第 k + 1 k+1 k+1 个中心点的概率为 P ( μ k + 1 = x ) = D 2 ( x ) ∑ x D 2 ( x ) P(\boldsymbol\mu_{k+1}=\boldsymbol x)=\frac{D^2(\boldsymbol x)}{\sum\limits_{\boldsymbol x}D^2(\boldsymbol x)} P(μk+1=x)=xD2(x)D2(x)

  上式的分母是在整个数据集上进行的求和,使所有样本被选为中心点的概率值和为1。上式的含义是,样本 x \boldsymbol x x被选为中心点的概率与其到当前中心点距离的平方成正比。我们重复这一过程,直到 K K K个聚类中心都被选出为止。

  下面,我们来实现k-means++的初始化函数。

def kmeanspp_init(dataset, K):
    # 随机第一个中心点
    idx = np.random.choice(np.arange(len(dataset)))
    centroids = dataset[idx][None]
    for k in range(1, K):
        d = []
        # 计算每个点到当前中心点的距离
        for data in dataset:
            dis = np.sum((centroids - data) ** 2, axis=-1)
            # 取最短距离的平方
            d.append(np.min(dis) ** 2)
        # 归一化
        d = np.array(d)
        d /= np.sum(d)
        # 按概率选取下一个中心点
        cent_id = np.random.choice(np.arange(len(dataset)), p=d)
        cent = dataset[cent_id]
        centroids = np.concatenate([centroids, cent[None]], axis=0)

    return centroids

  我们已经预留了初始化函数的接口,只需要将参数从random_init替换为kmeanspp_init就可以测试k-means++算法的表现了。从绘制的迭代中间结果可以明显看出,用k-means++算法选择的初始中心点互相之间的距离非常远,从而收敛速度也要快很多。大家可以修改随机种子,观察随机初始化和k-means++初始化对随机种子的敏感程度。

cent, cluster = Kmeans(dataset, 4, kmeanspp_init)

在这里插入图片描述

四、Sklearn中的k-means算法

  使用scikit-learn库中cluster模块的KMeans类可以实现KMeans聚类算法对数据进行聚类,KMeans类的基本使用格式和常用参数说明如下:

class sklearn.cluster.KMeans(n_clusters=8, *, init=‘k-means++’, n_init=10, max_iter=300, tol=0.0001)

参数名称参数说明
n_clusters接收int。表示要形成的簇数以及生成的质心数。默认为8。
init接收方法名。表示所选择的初始化方法,可选’k-means ++‘,‘random’,ndarray,callable。默认为’k-means ++’。
n_init接收int。表示K均值算法将在不同质心下运行的次数。默认为10。
max_iter接收int。表达单次运行的K均值算法的最大迭代次数。默认为300。
tol接收float。表示两个连续迭代的聚类中心的差异,以声明收敛。默认为1e-4。

  选择K个算法的流程如下:首先先选择K个聚类个数.直接生成K个中心作为均值定量,或者随机选择K个均值定量,然后作为聚类中心。对每个点确定其聚类中心点。再计算其聚类新中心。重复以上步骤直到满足收敛要求。(通常就是确定的中心点不再改变)。

  Kmeans的流程可以用以下一组图表示。

from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
blobs = make_blobs(random_state=7,centers=3)
X_blobs = blobs[0]
plt.scatter(X_blobs[:,0],X_blobs[:,1],c='r',edgecolors='k')
plt.show()

在这里插入图片描述

from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3)
kmeans.fit(X_blobs)
y_kmeans = kmeans.predict(X_blobs)
plt.scatter(X_blobs[:, 0], X_blobs[:, 1], c=y_kmeans, s=50)
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1],marker='x',c='r', s=200, alpha=0.5)
plt.show()

在这里插入图片描述

  我们先设置了一个K值为3,然后我们先随机从数据中找出三点作为三个均值定量,然后在计算所有数据各点到质心的距离,然后将是数据分配给距离最近的一类,用不同的颜色表示数据所属各类,然后经过第一轮的迭代后从各类中可以计算新的均值定量,然后计算每个数据点到个类之间的最近距离分到该类里面,重复迭代上述步骤。最终得到了一个合适的均值定量来表示我们的类别。当然在实际运用该算法时,一般会多以迭代,才能得到理想的结果。

  通过下列代码观察Kmeans算法的聚点,并观察决策边界。

# 导入必要的库
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans

# 生成带有3个中心的随机数据点
blobs = make_blobs(random_state=7, centers=3)
X_blobs = blobs[0]

# 绘制原始数据点
plt.scatter(X_blobs[:, 0], X_blobs[:, 1], c='r', edgecolors='k')

# 创建KMeans聚类模型,设置聚类数为3
kmeans = KMeans(n_clusters=3)
kmeans.fit(X_blobs)

# 定义图形的边界
X_min, X_max = X_blobs[:, 0].min() - 0.5, X_blobs[:, 0].max() + 0.5
y_min, y_max = X_blobs[:, 1].min() - 0.5, X_blobs[:, 1].max() + 0.5
# 创建网格用于绘制决策边界
xx, yy = np.meshgrid(np.arange(X_min, X_max, .02), np.arange(y_min, y_max, .02))

# 使用KMeans模型预测网格上的每个点的聚类
Z = kmeans.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

# 创建新的图形并清空之前的内容
plt.figure(1)
plt.clf()
# 绘制聚类决策边界
plt.imshow(Z, interpolation='nearest', extent=(xx.min(), xx.max(), yy.min(), yy.max()), cmap=plt.cm.summer, aspect='auto', origin='lower')
# 绘制原始数据点
plt.plot(X_blobs[:, 0], X_blobs[:, 1], 'r.', markersize=5)
# 绘制聚类中心
centroids = kmeans.cluster_centers_
plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', s=150, linewidths=3, color='b', zorder=10)
# 设置图形的显示范围
plt.xlim(X_min, X_max)
plt.ylim(y_min, y_max)
# 隐藏坐标轴刻度
plt.xticks(())
plt.yticks(())
# 显示图形
plt.show()

在这里插入图片描述

  看过此算法后,我们很容易与KNN算法搞混,两者都有一个相似的过程,就是都需要找到某一个点最近的点,二者都采用了最近邻的思想。其实两者的差别还是挺大的,Kmeans算法是无监督学习的聚类算法,而KNN算法是监督学习的分类算法。KNN算法基本不需要训练,只要从测试集里面根据距离计算公式找到K个点,用这K个点表示测试机集的类别即可,而Kmeans算法有明显的训练过程,需要反复迭代找到K个类别的最佳质心来决定数据的类别。

Kmeans算法的优点

  1. 原理简单、实现容易,是解决聚类问题的一种经典算法,保持可伸缩性和高效率,当数据集是密集的,它的效果较好。
  2. 算法的可解释性较强,只要需要调参的的参数只有分类数K。

Kmeans算法的缺点

  1. 必须事先给出K值,而且对初值敏感,对于不同的初始值,可能会导致不同结果。
  2. 对躁声和孤立点数据敏感。
  3. 采用迭代方法,得到的结果只是局部最优。

五、拓展:Sklearn中的层次聚类和密度聚类

(一)层次聚类

  使用scikit-learn库中cluster模块的AgglomerativeClustering类可以实现层次聚类算法对数据进行聚类,AgglomerativeClustering类的基本使用格式和常用参数说明如下:

class sklearn.cluster.AgglomerativeClustering(n_clusters=2, *, affinity='euclidean', memory=None, connectivity=None, compute_full_tree='auto', linkage='ward', distance_threshold=None)

参数名称参数说明
n_clusters接收int or None。表示要查找的集群数。默认为2。
affinity接收str or callable。表示用于计算链接的度量。默认为’euclidean’。
memory接收具有joblib的内存str或对象。表示用于缓存树计算的输出。默认为None。
connectivity接收数组或可调用的连接对象。表示连接的矩阵。默认为None。
compute_full_tree是否计算完整的聚类树,默认是 ‘auto’。
linkage连接策略,默认是 ‘ward’,可选择 ‘average’, ‘complete’, ‘single’。
distance_threshold接收float。表示链接距离的阈值。默认为None。

  层次聚类算法类,是许多基于相同原则构建的聚类算法,算法的原理如下:所谓层次聚类就是让算法在一开始的时候,将每一个点作为一个类别,每一次进行算法合并两个最近的两类,直到满足某个条件为止。sklearn中实现该算法的满足条件是类别的个数,当剩下指定个数的类时,算法自动停止。

  这里的参数重要的是链接准则,他的意思是如何寻找最相近的点。sklearn库中包含三种链接方式:ward:是默认选项,通过挑选两个类来合并,类中的方差增加最小通过这中链接方式通常得到大小差不多相等的簇。average链接:将簇中所有点之间平均距离最小的两个类合并。complete链接:也称为最大链接,将簇中点之间最大距离最小的两个类合并。ward适用于大多数数据集。如果类中的成员个数非常不同,那么average或complete可能效果更好。single连接法(单链接):是指使用最小距离来合并簇。这意味着在两个簇之间,距离最近的两个点的距离被用作簇间距离。这种方法倾向于形成长而狭的簇,可能导致链状结构的形成。适用于处理形状不规则的数据集,但也可能对噪声和离群点敏感。

  下面是对数据集采用三种链接准则得到的结果。程序如下:

# 导入必要的库
from sklearn.datasets import make_blobs  # 生成随机数据的模块
from sklearn.cluster import AgglomerativeClustering  # 导入层次聚类模型
import numpy as np  # 数值计算库
import matplotlib.pyplot as plt  # 绘图库
from itertools import cycle  # 用于循环颜色的迭代器模块

# 定义数据中心
centers = [[1, 1], [-1, -1], [1, -1]]
# 生成随机数据,n_samples是样本数量,centers是中心位置,cluster_std是簇的标准差
X, labels_true = make_blobs(n_samples=2000, centers=centers, cluster_std=0.5, random_state=22)
# 创建层次聚类模型,使用ward链接方法,期望聚类数为4
ac = AgglomerativeClustering(linkage='ward', n_clusters=4)
# ac = AgglomerativeClustering(linkage='average', n_clusters=4)
# ac = AgglomerativeClustering(linkage='complete', n_clusters=4)

# 训练模型并对数据进行聚类
ac.fit(X)

# 获取每个数据点的分类标签
labels = ac.labels_
# 绘图
plt.figure(1)  # 创建一个新图形
plt.clf()  # 清空当前图形
# 定义颜色循环,使用'r','g','c','y'四种颜色
colors = cycle('rgcy')
# 遍历每个聚类标签(0到3),并绘制相应的数据点
for k, col in zip(range(4), colors):
    # 创建一个布尔数组,标识哪些点属于当前聚类
    my_members = labels == k
    # 绘制属于当前聚类的点,X[my_members,0]为横坐标,X[my_members,1]为纵坐标
    plt.plot(X[my_members, 0], X[my_members, 1], col + '.')
# 显示绘制的图形
plt.show()

在这里插入图片描述

层次聚类算法的优点

  1. 距离和规则的相似度容易定义,限制少
  2. 不需要预先制定聚类数
  3. 可以发现类的层次关系

层次聚类算法的缺点

  1. 计算复杂度太高
  2. 奇异值也能产生很大影响
  3. 算法很可能聚类成链状

(二)密度聚类之DBSCAN算法

  使用scikit-learn库中cluster模块的DBSCAN类可以实现密度聚类算法对数据进行聚类,DBSCAN类的基本使用格式和常用参数说明如下:

class sklearn.cluster.DBSCAN(eps=0.5, *, min_samples=5, metric='euclidean', metric_params=None, algorithm='auto', leaf_size=30, p=None, n_jobs=None)

参数名称参数说明
eps接收float。表示邻域半径。默认为0.5。
min_samples接收int。表示一个点附近的样品数量(或总重量)被视为核心点。默认为5。
metric接收string or callable。表示计算要素阵列中实例之间的距离时使用的度量。默认为’euclidean’。
metric_params接收dict。表示度量功能的其他关键字参数。默认为None。
algorithm接收算法名称。表示NearestNeighbors模块将使用该算法来计算逐点距离并查找最近的邻居。默认为’auto’。
leaf_size接收int。影响ball_tree和kd_tree的构建和查询速度的参数。较大的值可能会导致更快的查询,但更慢的构建时间。默认为30。
p接收float。在使用Minkowski距离时的参数,可以设置为1(曼哈顿距离)或2(欧氏距离)。默认为None。
n_jobs接收int。表示要运行的并行作业数。默认为None。

  DBSCAN聚类算法是一种基于密度的算法,这一类算法通常通过根据数据的紧密程度进行分类,如果一个数据属于该类,则在其附近一定存在属于该类的数据点。通过紧密分布的数据集分为一类,就得到了一个聚类类别。通过将所有数据划分为不同类别,就得到了最终的聚类类别结果。该算法将具有足够密度的区域划分为一类,并在具有噪声的数据集中能划分出不同形状的类别,它将类定义为密度相连的点的最大集合。那么它是怎么基于密度工作的呢?

  在一个数据集中,我们的目标是把数据中密度相近的聚为一类。我们先从数据中选择一点,然后按照一定规则在这里寻找密度相近的点组成一类。其他的数据点也是如此。这个规则就是根据这个随即被选中的数据点画一个圆圈,规定这个圆的半径以及圆内最少包含的数据数,然后在包含在内的数据中转移中心点,那么这个圆圈的圆心就转移到这个内部样本点,继续去圈附近其它的数据点,然后一直重复上述过程,继续增加数据点直到没有符合条件的数据为止。

  基于密度这点有什么好处呢,我们知道k-means聚类算法只能根据距离进行计算,而现实中还会有各种形状的图,比如环形图,这个时候,k-means算法就不适用。于是就想到根据数据的密度进行分类。

  上述基本是DBSCAN算法的主要内容了,是不是很简单,但是我们还有三个问题没有考虑。第一个是一些数据远离于其他数据点,这些点不在任何一类的周围,在DBSCAN中,我们一般将这些样本点标记为噪音点。第二个是距离的度量问题,即如何计算某样本和核心对象样本的距离。在DBSCAN中,一般采用最近邻思想,采用某一种距离度量来衡量样本距离,比如欧式距离。这和KNN分类算法的最近邻思想完全相同。

  DBSCAN这个算法包括了重要的两个参数,这两个参数比较难指定,公认的指定方法是以下两个:

  • 半径:半径是比较重要的一个点,如果选择过大了,圈住点就多了,类别的个数就少了,反之圈住的点少,类别就增加,这对最后生成的结果非常重要。
  • MinPts:这个参数就是圈住的点的个数,也相当于是一个密度,一般我们先让这个值尽可能地小,然后进行多次尝试算法。

  下面我们对DBSCAN算法进行应用。首先我们生成一个环形数据来测试算法。

from sklearn.datasets.samples_generator import make_circles
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
X, y_true = make_circles(n_samples=2000, factor=0.5,noise=0.1)  # 环状数据

# DBSCAN算法
dbscan = DBSCAN(eps=.1, min_samples=10)
dbscan.fit(X)  # 该算法对应的两个参数
plt.scatter(X[:, 0], X[:, 1], c=dbscan.labels_)
plt.show()

在这里插入图片描述

  从图中可以看出,算法划分的方法符合我们的思维,并且基本做到了完美划分。接下来试验一下对于双半月数据,算法能不能做到好的预测。

from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
X, y_true = make_moons(n_samples=2000, noise=0.1)    # 双半月数据

# DBSCAN算法
dbscan = DBSCAN(eps=.1, min_samples=10)
dbscan.fit(X)  # 该算法对应的两个参数
plt.scatter(X[:, 0], X[:, 1], c=dbscan.labels_)
plt.show()

在这里插入图片描述

  从图中看出,依旧能建立较好的模型。测试完之后大家可能感觉没有那么神奇,因为这种方法符合我们的思维,但是这是由计算机划分出来的。与Kmeans算法和层次聚类算法进行对比,我们就能知道这个算法的优越之处了。

from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans, AgglomerativeClustering

# 创建数据集
X, y_true = make_moons(n_samples=2000, noise=0.1)
# KMeans聚类
kmeans = KMeans(n_clusters=2)
kmeans.fit(X)
# 层次聚类
ac = AgglomerativeClustering(n_clusters=2)
ac.fit(X)

# 创建子图
fig, axs = plt.subplots(1, 2, figsize=(12, 5))
# KMeans图
axs[0].scatter(X[:, 0], X[:, 1], c=kmeans.labels_, cmap='viridis')
axs[0].set_title('KMeans Clustering')
# Agglomerative Clustering图
axs[1].scatter(X[:, 0], X[:, 1], c=ac.labels_, cmap='viridis')
axs[1].set_title('Agglomerative Clustering')

# 显示图形
plt.tight_layout()
plt.show()

在这里插入图片描述

# 层次聚类
ac = AgglomerativeClustering(n_clusters=2)
ac.fit(X)
plt.scatter(X[:, 0], X[:, 1], c=ac.labels_)
plt.show()

在这里插入图片描述

  可以看到如果分为两类,这种划分方式不符合我们的思维。所以对于不同的问题要选择合适的算法才能解决。

DBSCAN算法的优点

  1. 速度快,不需要提前设定K值大小,DBSCAN不需要事先知道要形成种类的数量。
  2. 对噪声不敏感。可以在聚类的同时发现异常点,对数据集中的异常点不敏感,能发现任意形状的簇。这是因为该算法能够较好地判断离群点,并且即使错判离群点,对最终的聚类结果也没什么影响。
  3. 聚类生成的种类没有偏倚,而Kmeans之类的聚类算法初始值对聚类结果有很大影响。

DBSCAN算法的缺点

  1. 对参数的设置敏感,当半径和密度变化时会很大程度影响结果。
  2. 当数据量较大时,要求的内存也大。
  3. 当空间密度不均匀、聚类间距差相差很大时,聚类质量较差。

:以上文中的数据集及相关资源下载地址:
链接:https://pan.quark.cn/s/a5fa36f23a77
提取码:viFn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2160835.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ANSYS Workbench随机球体多孔结构三维模型

三维多孔结构广泛存在于材料科学、生物医学工程、土木工程等领域,如泡沫金属、骨组织、过滤介质等,通过ANSYS Workbench对三维多孔结构进行有限元模拟,是对其进行性能分析的有效手段。 在ANSYS内建立多孔结构模型可采用CAD随机球体插件专业…

Linux查看java服务所在目录

1、java服务jar的PID jps -l 2、定位目录 ls -l /proc/[pid]/cwd

关于QSizeGrip在ui界面存在布局的情况下的不显示问题

直接重写resizeEvent你会发现:grip并没有显示 void XXXXX::resizeEvent(QResizeEvent *event) {QWidget::resizeEvent(event);this->m_sizeGrip->move(this->width() - this->m_sizeGrip->width() - 3,this->height() - this->m_sizeGrip->…

[spring]MyBatis介绍 及 用MyBatis注解操作简单数据库

文章目录 一. 什么是MyBatis二. MyBatis操作数据库步骤(使用注解)创建工程创建数据库创建对应实体类配置数据库连接字符串写持久层代码单元测试 三. MyBatis基础操作 使用注解打印日志参数传递增删改查 一. 什么是MyBatis 简单来说 MyBatis 是更简单完成程序和数据库交互的框架…

langchain的构成

1.简介 langchain的构成其包含langchain-core,langchain-community,langchain,langgraph,langserve,langSmith。 2,构件的详解 ‌LangChain Core‌ ‌LangChain Core‌是LangChain框架的核心组成部分,它包含了不同组件的基本抽象以及将它们组合在一起…

ruoyi-flowable流程设计配置的表单时,级联选择如何配置??

🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收…

为什么自学python那么难?

在科技日新月异的今天,编程能力已成为一项备受追捧的技能。仿佛一夜之间,各种编程学习资源如雨后春笋般涌现,让人眼花缭乱。然而,许多人投身于自学编程的行列,却往往在半路折戟沉沙。究竟是什么原因让自学编程变得如此…

如何重置企业/媒体/组织/个体户类型管理员微信号

请您通过浏览器打开该网页https://mp.weixin.qq.com/acct/findacct?actionscan重置公众号绑定邮箱和管理员微信号, 在申请找回帐号的页面填写的对公账户信息和运营者信息可以和注册不一致,完成找回后,管理员微信号会同步更新; …

【小程序】微信小程序课程 -3 快速上手之常用方法

目录 1、 对话框 1.1 模态对话框 1.2 消息对话框 2、 存储 2.1 同步 2.1.1 同步保存数据 2.1.2 同步获取数据 2.1.3 同步删除数据 2.1.4 同步清空数据 2.2 异步 2.2.1 异步保存数据 2.2.2 异步获取数据 2.2.3 异步删除数据 2.2.4 异步清空数据 3、 上拉加载更多…

代码随想录算法训练营第三十八天 | 322. 零钱兑换,279.完全平方数,139.单词拆分,多重背包

322.零钱兑换 题目链接 解题过程 递推公式写对了&#xff0c;但对于特殊情况的案例没有想清楚&#xff0c;如不能凑成则需返回-1dp[i] min(dp[i], dp[i - coin] 1); 完全背包 class Solution { public:int coinChange(vector<int>& coins, int amount) {vector…

SSM影院订票系统—计算机毕业设计源码35370

摘 要 随着互联网时代的到来&#xff0c;同时计算机网络技术高速发展&#xff0c;网络管理运用也变得越来越广泛。因此&#xff0c;建立一个SSM影院订票系统&#xff1b;订票系统的管理工作系统化、规范化&#xff0c;也会提高平台形象&#xff0c;提高管理效率。 本影院订票系…

11周年 | 初心不改,焕新前行,奔赴下一个10年!

2024年8月13日&#xff0c;爱加密正式迎来了11岁生日&#xff0c;在爱加密肩负着崇高使命踏浪而行的10年间&#xff0c;蓝绿色的品牌标识一直伴于左右。随着时代的变迁以及市场需求的不断变化&#xff0c;企业同样也需要在品牌上做出创新递进&#xff0c;从而更加适应市场竞争的…

AI知识库助力电商企业打造精准营销策略

在数字化时代&#xff0c;电商行业的竞争日益激烈&#xff0c;消费者需求的多样化和个性化趋势愈发明显。为了在这场没有硝烟的战争中脱颖而出&#xff0c;电商企业纷纷借助人工智能技术&#xff0c;特别是AI知识库&#xff0c;来打造更加精准、高效的营销策略。本文将深入探讨…

【运维自动化-作业平台】如何使用全局变量之命名空间类型?

命名空间类型的全局变量主要适用场景是同一批主机在多个步骤间需要传递独立的变量值&#xff0c;比如内网ip、hostame&#xff0c;每台主机都是不同的变量值。而字符串变量是全局针对所有主机所有步骤都是一样的变量值。实操演示 例&#xff1a;定义一个local_ip的命名空间变量…

单利复利计算器使用方法

单利复利计算器使用方法 背景 这个工具主要是小部分人用&#xff0c;因为以前要算个单利复利的时候&#xff0c;搜索出来的工具上来就要获取你的手机号&#xff0c;进去之后再收费。如果使用频繁的话&#xff0c;可以购买他们的更多服务&#xff0c;产品功能更多更完善。偶尔…

年轻用户对Facebook的使用趋势分析

在社交媒体的蓬勃发展中&#xff0c;Facebook作为全球最大的社交平台之一&#xff0c;尽管面临着来自新兴平台的竞争&#xff0c;仍然在年轻用户中扮演着重要角色。然而&#xff0c;年轻用户对Facebook的使用方式和趋势却在不断变化。本文将探讨年轻用户对Facebook的使用趋势&a…

性能测试工具——JMeter

目录 一、JMeter介绍 1、下载安装JMeter 2、打开JMeter 方式一&#xff1a; 方式二&#xff1a; 3、JMeter基础设置 4、JMeter基本使用流程 &#xff08;1&#xff09;启动JMeter &#xff08;2&#xff09;在测试计划下添加线程组 &#xff08;3&#xff09;在 “线…

防止企业数据泄露 | 信息数据电脑保护系统 | 天锐DLP数据安全

在当今这个高度信息化的时代&#xff0c;数据已跃升为企业运营不可或缺的核心战略资源&#xff0c;而面对企业内部终端上海量的数据信息&#xff0c;及时、准确地识别出重要的敏感数据是一项关键任务&#xff0c;它直接关系到企业的数据安全、合规性以及业务风险的控制。 【地址…

鸿蒙HarmonyOS NEXT系统揭秘:跨端迁移与多端协同

随着科技的飞速发展&#xff0c;万物互联的时代已经悄然来临。 在这个背景下&#xff0c;华为鸿蒙HarmonyOS NEXT系统的最新动向无疑成为了业界关注的焦点。 近日&#xff0c;关于鸿蒙操作系统将多设备协同功能细分为“跨端迁移”与“多端协同”的消息不胫而走&#xff0c;这…

基于单片机的太阳能热水器控制系统的研究-设计说明书

设计摘要&#xff1a; 本研究旨在设计和实现基于单片机的太阳能热水器控制系统。太阳能热水器是一种有效利用太阳能来加热水的设备&#xff0c;在节能和环保方面具有显著的优势。本研究通过使用单片机技术&#xff0c;将传统的太阳能热水器与智能控制相结合&#xff0c;提高了…