<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>第 11 章 聚类分析 on 《从零学AI指南手册》</title>
		<link>https://mlwithme.github.io/ml/chapter11/</link>
		<description>Recent content in 第 11 章 聚类分析 on 《从零学AI指南手册》</description>
		<generator>Hugo</generator>
		<language>zh_CN</language>
		
		
		
		
			<atom:link href="https://mlwithme.github.io/ml/chapter11/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>11.1 聚类算法的思想</title>
				<link>https://mlwithme.github.io/ml/chapter11/f9d9305a55a548a1/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/f9d9305a55a548a1/</guid>
				<description>&lt;p&gt;经过前面一系列的介绍，我们已经接触了多种回归和分类算法，并且这些算法有一个共同的特点，也就是它们都是有监督的学习算法。接下来，我们将开始学习一类经典的无监督机器学习算法——聚类算法。如图11-1所示便是本章内容的学习路线图，整体包含有5种聚类算法的原理及实现过程以及聚类算法中的两类评价指标和K值的选取与分析。同时，对于每个算法的分阶段学习路线将在各小节中进行说明。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/ml/240822152048.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 11-1 聚类算法学习路线图&lt;/center&gt;&#xA;&lt;h1 id=&#34;111-聚类算法的思想&#34;&gt;11.1 聚类算法的思想&lt;a class=&#34;anchor&#34; href=&#34;#111-%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95%e7%9a%84%e6%80%9d%e6%83%b3&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在正式介绍聚类之前，我们先从感性上认识一下什么是聚类。聚类算法的核心思想就是将具有相似特征的事物“聚”在一起，也就是说“聚”是一个动词。俗话说： 人以群分，物以类聚，说的就是这个道理。&lt;/p&gt;&#xA;&lt;p&gt;如图11-2所示，此图为3种类别的数据样本图，其中每种形状表示一个类别。聚类算法的目的就是将各个类别的样本点分开，也就是将同一种类别的样本点聚在一起。此时可能有人会问： 这不是和分类模型一样吗？刚刚接触聚类的读者难免会有这样一个疑问，即聚类和分类的区别在哪儿？聚类算法的核心思想是将具有相似特征的事物聚在一起。也就是说，聚类算法最终只能告诉我们哪些样本属于同一个类别，而不能告诉我们这些样本具体属于什么类别。因此，聚类算法在训练过程中并不需要每个样本所对应的真实标签，而分类算法却不行。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/ml/p10-1.png&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-2 聚类算法思想示意图&lt;/center&gt;&#xA;&lt;p&gt;假如这里有100个样本的病例数据（包含正样本和负样本），并且通过聚类算法聚类后可以将原始数据划分成两堆，其中一堆里面有40个样本且均为一个类别，而剩下的一堆里面有60个样本且也为同一个类别，但现在这两堆究竟哪一个代表正样例，哪一个代表负样例，这是聚类算法无法告诉我们的。同时，在聚类算法中这“堆”就被称为聚类后所得到的簇（Cluster）。&lt;/p&gt;&#xA;&lt;p&gt;同时，由于不同领域的数据样本通常存在着不同的簇结构，因此也就衍生得到了不同的聚类算法。因此，除了图11-2中这种最为常见的簇结构以外，还有图11-24和图11-31所示的簇结构，其分别对应的就是在11.10和11.11节将要介绍的基于密度和层次的聚类算法。&lt;/p&gt;&#xA;&lt;p&gt;至此，我们相信读者已经明白了聚类算法的核心思想。那么，聚类算法是如何完成这一过程的呢？&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.2 Kmeans聚类算法</title>
				<link>https://mlwithme.github.io/ml/chapter11/e635df24de32487a/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/e635df24de32487a/</guid>
				<description>&lt;h1 id=&#34;112-kmeans聚类算法&#34;&gt;11.2 Kmeans聚类算法&lt;a class=&#34;anchor&#34; href=&#34;#112-kmeans%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在11.1节中我们介绍过，聚类的思想是将具有同种特征的样本聚在一起。换句话说，同一个簇中的样本点之间都具有高度的相似性，而不同簇中的样本点则具有较低的相似性，因此，聚类算法的本质又可被看成不同样本点间相似性的度量，聚类的目的就是将相似度较高的样本点放到一个簇中。由于不同类型的聚类算法有着不同的聚类原理，以及相似性评判标准。下面我们首先介绍聚类算法中最常用的Kmeans聚类算法，其对应的学习路线如图11-3所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/ml/240427155749.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 11-3 Kmeans聚类算法学习路线图&lt;/center&gt;&#xA;&lt;p&gt;如图11-3所示便是Kmeans聚类算法的学习路线图，在接下来的3节内容中我们将逐一对上述内容进行介绍。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1121-kmeans算法思想&#34;&gt;11.2.1 Kmeans算法思想&lt;a class=&#34;anchor&#34; href=&#34;#1121-kmeans%e7%ae%97%e6%b3%95%e6%80%9d%e6%83%b3&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在上面我们说到，聚类算法的核心思想就是将具有相似特征的样本点聚在一起，而不同聚类算法之间的差异则表现在对于样本点相似的定义上。对于Kmeans聚类算法来说，它的核心思想在于通过计算样本点之间的欧式距离来衡量样本间的相似性，距离越近的两个样本点则越相似，则越有可能被划分到同一个簇结构中，最终使得同一簇内的样本点尽可能接近，而不同簇之间的样本点尽可能远离。因此，当Kmeans聚类算法完成整个聚类过程以后，将会得到类似图11-2所示的结果。下面，我们来看如何在sklearn中使用Kmeans聚类算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1122-kmeans示例代码&#34;&gt;11.2.2 Kmeans示例代码&lt;a class=&#34;anchor&#34; href=&#34;#1122-kmeans%e7%a4%ba%e4%be%8b%e4%bb%a3%e7%a0%81&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在sklearn中，可以通过语句&lt;code&gt;from sklearn.cluster import KMeans&lt;/code&gt;来完成对Kmeans模型的导入。在这之后，我们仍旧可以通过前面介绍的3步走策略完成整个聚类任务。完整代码可参见 &lt;code&gt;AllBooKCode/Chapter11/C02_kmeans_train.py&lt;/code&gt; 文件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 载入数据集&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在开始聚类之前，首先同样需要载入相应的数据集。在这个示例中，使用的依旧是iris数据集，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;sklearn.datasets&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; load_iris&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;load_data&lt;/span&gt;():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     data &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; load_iris()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     x, y &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;data, data&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;target&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; x, y&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;2. 训练模型&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在完成数据集载入后则需要导入sklearn中的&lt;code&gt;Kmeans&lt;/code&gt;聚类模型并进行聚类，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;sklearn.cluster&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; KMeans&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;sklearn.metrics.cluster&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; adjusted_rand_score&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;train&lt;/span&gt;(x, y, K):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     model &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; KMeans(n_clusters&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;K)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     model&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;fit(x)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     y_pred &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; model&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;predict(x)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;     ari &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; adjusted_rand_score(y, y_pred)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;ARI: &amp;#34;&lt;/span&gt;, ari)&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 0.716&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第1行用来导入sklearn中的&lt;code&gt;KMeans&lt;/code&gt;聚类模型。第2行用来导入聚类评估指标，其范围为$[-1,1]$，值越大表示结果越好，这部分内容将在第11.6节中进行介绍。第4行代码则用来初始化&lt;code&gt;KMeans&lt;/code&gt;模型，参数&lt;code&gt;n_clusters&lt;/code&gt;表示指定数据集中的簇数量。第5~8行则用来分别进行聚类、预测和模型评估。&lt;/p&gt;&#xA;&lt;p&gt;以上代码便是使用sklearn搭建一个聚类模型的全部代码，可以看到其过程其实非常简单，而这一切得益于sklearn的友好的接口设计风格。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1123-kmeans算法原理&#34;&gt;11.2.3 Kmeans算法原理&lt;a class=&#34;anchor&#34; href=&#34;#1123-kmeans%e7%ae%97%e6%b3%95%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Kmeans聚类算法也被称为K均值聚类，其主要原理可以总结为以下几点[1]：&lt;/p&gt;&#xA;&lt;p&gt;(1) 随机选择K个样本点作为K个簇的初始簇中心；&lt;/p&gt;&#xA;&lt;p&gt;(2) 计算每个样本点与这K个簇中心的相似度，并将该样本点划分到与之相似度最高的簇中心所对应的簇中；&lt;/p&gt;&#xA;&lt;p&gt;(3) 根据每个簇中现有的样本，重新计算每个簇的簇中心；&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.3 Kmeans算法求解</title>
				<link>https://mlwithme.github.io/ml/chapter11/e75b8efa232249ab/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/e75b8efa232249ab/</guid>
				<description>&lt;h1 id=&#34;113-kmeans算法求解&#34;&gt;11.3 Kmeans算法求解&lt;a class=&#34;anchor&#34; href=&#34;#113-kmeans%e7%ae%97%e6%b3%95%e6%b1%82%e8%a7%a3&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;到目前为止，相信各位读者已经对Kmeans聚类算法的过程有了一个清楚的了解，但是我们应该如何从数学的角度来对其进行描述呢？正如我们在介绍线性回归时所讲解的那样，对于聚类算法来讲我们同样应该找到一个目标函数来对聚类结果的好坏进行刻画。在前面我们介绍过，聚类的本质可被看成不同样本间相似度比较的过程，把相似度较高的样本点放到一个簇中，而把相似度较低的样本点放到不同的簇中。既然如此，应该怎么来衡量样本间的相似度呢？&lt;/p&gt;&#xA;&lt;p&gt;一种最常见的做法当然是计算两个样本间的欧氏距离，即两个样本点离得越近就代表着两者间的相似度越高，并且这也是Kmeans聚类算法中的衡量标准。因此，根据这样的准则就可以将Kmeans聚类算法的目标函数定义为所有样本点到其对应簇中心距离的总和，以此来刻画聚类结果的好坏程度。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1131-kmeans算法目标函数&#34;&gt;11.3.1 Kmeans算法目标函数&lt;a class=&#34;anchor&#34; href=&#34;#1131-kmeans%e7%ae%97%e6%b3%95%e7%9b%ae%e6%a0%87%e5%87%bd%e6%95%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;如图11-5所示，图(a)和图(b)分别为同一数据集的两种不同聚类结果，其中同种颜色表示聚类后被划分到同一个簇中，黑色圆点为聚类后的簇中心。从可视化结果来看，图(a)中的聚类结果肯定好于图(b)中的聚类结果。也就是说，可以通过最小化目标函数$d=d_1+d_2,+\cdots,+d_{10}$来得到最优解。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;500&#34; src=&#34;https://mlwithme.github.io/images/ml/p10-3.png&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-5 Kmeans聚类目标函数图形&lt;/center&gt;&#xA;&lt;p&gt;设$X=\{X_1,X_2,.\cdots,X_n\}$为一个含有$n$个样本的数据集，其中第$i$个样本表示为$X_i=\{x_{i1},x_{i2},\cdots,x_{im}\}$，$m$为样本特征的数量。样本分配矩阵$U$是一个$n\times k$的0-1矩阵（只含有0和1），$u_{ip}$表示第$i$个样本被分到第$p$个簇中。$Z=\{{{Z}_{1}},{{Z}_{2}},\cdots ,{{Z}_{k}}\}$为$k$个簇中心向量，其中$Z_p=\{z_{p1},z_{p2},\cdots,z_{pm}\}$为第$p$个簇中心，则Kmeans聚类算法的目标函数可以写为&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;&amp;P(U,Z)=\sum\limits_{p=1}^{k}{\sum\limits_{i=1}^{n}{{{u}_{ip}}}}\sum\limits_{j=1}^{m}{{{({{x}_{ij}}-{{z}_{pj}})}^{2}}}\\[1ex]&#xA;&amp;\text{s.t.} \;\sum\limits_{p=1}^{k}{{{u}_{ip}}}=1&#xA;\end{aligned}&#xA;\tag{11-1}&#xA;$$&lt;p&gt;&#xA;虽然式(11-1)看起来稍微有点复杂，但是其表示的含义就是求各个样本点到其对应簇中心的距离和。由于一个数据集有多个簇，每个簇中有多个样本，每个样本又有多个维度，因此式(11-1)中就出现了3个求和符号。其次，我们再以图11-5为例来简单介绍一下分配矩阵$U$。由图11-5(a)可知，数据集中一共有两个簇，并且假设前5个样本为一个簇，后5个样本为一个簇，则其对应的分配矩阵为&#xA;&lt;/p&gt;&#xA;$$&#xA;{{U}_{[10\times 2]}}={{\left[ \begin{matrix}&#xA;   1 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 0  \\&#xA;   0 &amp; 0 &amp; 0 &amp; 0 &amp; 0 &amp; 1 &amp; 1 &amp; 1 &amp; 1 &amp; 1  \\&#xA;\end{matrix} \right]}^{T}}\tag{11-2}&#xA;$$&lt;h2 id=&#34;1132-求解簇中心矩阵&#34;&gt;11.3.2 求解簇中心矩阵$Z$&lt;a class=&#34;anchor&#34; href=&#34;#1132-%e6%b1%82%e8%a7%a3%e7%b0%87%e4%b8%ad%e5%bf%83%e7%9f%a9%e9%98%b5&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;同SVM求解过程一样，对于目标函数式(11-1)的求解依旧需要借助于拉格朗日乘数法。由目标函数式(11-1)可知，这里一共需要求解的未知参数包括两个，簇中心矩阵$Z$和簇分配矩阵$U$。&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.4 从零实现Kmeans聚类算法</title>
				<link>https://mlwithme.github.io/ml/chapter11/60e49a33d1aa4f50/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/60e49a33d1aa4f50/</guid>
				<description>&lt;h1 id=&#34;114-从零实现kmeans聚类算法&#34;&gt;11.4 从零实现Kmeans聚类算法&lt;a class=&#34;anchor&#34; href=&#34;#114-%e4%bb%8e%e9%9b%b6%e5%ae%9e%e7%8e%b0kmeans%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;通过11.3节内容的介绍，我们已经知道了Kmeans聚类算法中两个关键未知变量的计算公式，接下来需要完成的就是对其进行编码实现。在11.2.3节中我们介绍过，聚类算法的步骤主要分为4个步骤，其中其中第4个步骤为循环迭代过程，因此整个聚类过程的关键在于前3步。接下来开始分别进行编码实现，完整示例代码可参见 &lt;code&gt;AllBooKCode/Chapter11/C04_kmeans.py&lt;/code&gt; 文件。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1141-随机初始化簇中心&#34;&gt;11.4.1 随机初始化簇中心&lt;a class=&#34;anchor&#34; href=&#34;#1141-%e9%9a%8f%e6%9c%ba%e5%88%9d%e5%a7%8b%e5%8c%96%e7%b0%87%e4%b8%ad%e5%bf%83&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Kmeans聚类算法的K个初始簇中心由随机初始化得到，因此这里可以借助Python中的&lt;code&gt;random.sample()&lt;/code&gt;方法实现，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;random&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;InitCentroids&lt;/span&gt;(X, K):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     n &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     rands_index &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;array(random&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sample(&lt;span style=&#34;color:#007020&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, n), K))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     centriod &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X[rands_index, :]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; centriod&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第3行用来得到数据集&lt;code&gt;X&lt;/code&gt;中一共有多少个样本点。第4行用来在数值$[0,n)$中随机取K个不重复的值。第5行则是以第4行得到的K个值为下标，在数据集中取对应的K个样本点，即簇中心。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1142-簇分配矩阵实现&#34;&gt;11.4.2 簇分配矩阵实现&lt;a class=&#34;anchor&#34; href=&#34;#1142-%e7%b0%87%e5%88%86%e9%85%8d%e7%9f%a9%e9%98%b5%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;对于簇分配矩阵的实现，根据式(11-5)可知，只需先遍历每个样本点，然后计算其到每个簇中心的距离并选择最近簇中心即可，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;findClostestCentroids&lt;/span&gt;(X, centroid):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     n &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     idx &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;zeros(n, dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;int&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;range&lt;/span&gt;(n):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;         subs &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; centroid &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt; X[i, :]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;         dimension2 &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;power(subs, &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         dimension_s &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sum(dimension2, axis&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;         idx[i] &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;where(dimension_s &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; dimension_s&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;min())[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;][&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; idx&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第3行用来初始化1个全0的n维向量，用于后续保存每个样本的簇索引。第4~8行用来分别遍历每个样本点，然后计算其到所有簇中心的距离，最后选择与之距离最近的簇中心。同时，需要注意的是，在实际的编码过程中其实并不需要通过一个形状为$n\times k$的分配矩阵来存储每个样本的分配信息，只需将每个簇进行编号，然后对每个样本点赋予一个对应的编号，因此，在上述代码中返回的&lt;code&gt;idx&lt;/code&gt;就是每个样本点距离其最近簇的簇编号。例如&lt;code&gt;idx=[0,1,2]&lt;/code&gt;表示这3个样本点分别属于第0个簇、第1个簇和第2个簇。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1143-簇中心矩阵实现&#34;&gt;11.4.3 簇中心矩阵实现&lt;a class=&#34;anchor&#34; href=&#34;#1143-%e7%b0%87%e4%b8%ad%e5%bf%83%e7%9f%a9%e9%98%b5%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;对于簇中心矩阵的计算，根据式(11-4)可知，只需先遍历K个簇，然后分别计算每个簇中所有样本点的平均中心即可，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;computeCentroids&lt;/span&gt;(X, idx, K):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     n, m &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     centriod &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;zeros((K, m), dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020&#34;&gt;float&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; k &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;range&lt;/span&gt;(K):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;         index &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;where(idx &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; k)[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 一个簇一个簇的分开计算&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;         temp &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X[index, :]  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# ? by m # 每次先取出一个簇中的所有样本&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         s &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sum(temp, axis&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;)&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 计算一个簇中，每个特征维度的累加和&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;         centriod[k, :] &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; s &lt;span style=&#34;color:#666&#34;&gt;/&lt;/span&gt; index&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 计算得到每个特征维度的均值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; centriod&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第3行用来初始化一个全0的簇中心矩阵。第4~8行分别用来遍历每个簇，然后计算每个簇的簇中心并将其保存到簇中心矩阵中。&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.5 Kmeans&#43;&#43;聚类算法</title>
				<link>https://mlwithme.github.io/ml/chapter11/c8b45d8a3d8c4cf4/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/c8b45d8a3d8c4cf4/</guid>
				<description>&lt;h1 id=&#34;115-kmeans聚类算法&#34;&gt;11.5 Kmeans++聚类算法&lt;a class=&#34;anchor&#34; href=&#34;#115-kmeans%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中，我们介绍了什么是聚类算法，并且还介绍了聚类算法中应用最为广泛的Kmeans聚类算法。从Kmeans聚类算法的原理可知，Kmeans在正式聚类之前首先需要完成的就是初始化K个簇中心。同时，也正是因为这个原因使Kmeans聚类算法存在着一个巨大的缺陷——收敛情况严重依赖于簇中心的初始化状况。试想一下，如果在初始化过程中很不巧地将K个（或大多数）簇中心都初始化到同一个簇中，则在这种情况下Kmeans聚类算法很大程度上都不会收敛到全局最优解。也就是说，当簇中心初始化的位置不合适时，聚类结果将会出现严重错误。在本节内容中我们将介绍一种基于Kmeans聚类算法改进而来的Kmeans++聚类算法，其学习路线如图11-6所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/ml/240427155853.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 11-6 Kmeans++算法学习路线图&lt;/center&gt;&#xA;&lt;h2 id=&#34;1151-kmeans算法思想&#34;&gt;11.5.1 Kmeans++算法思想&lt;a class=&#34;anchor&#34; href=&#34;#1151-kmeans%e7%ae%97%e6%b3%95%e6%80%9d%e6%83%b3&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;如图11-7所示的聚类过程仍旧是通过Kmeans聚类算法在11.2节中所用到的人造数据集上得到的聚类结果。只不过不同的是在进行聚类时人为地将3个簇中心初始化到同一个簇中了。在图11-7中，iter=0表示未开始聚类前根据每个样本的真实簇标签所展示的结果，其中蓝色、绿色和橙色分别表示3个簇的分布情况，而3个黑色圆点为初始化的簇中心。从图11-7中可以发现，Kmeans在进行完第10次迭代后，将最上面的1个簇划分为了2个簇，将下面的2个簇划分成了1个簇。同时，当进行完第30次迭代后，可以发现算法已经开始收敛，但后续簇中心却没有发生任何变化，因此最终的结果仍旧是将上面1个簇分为2个簇，将下面的2个簇划分为1个簇。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;550&#34; src=&#34;https://mlwithme.github.io/images/ml/p10-4.png&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-7 Kmeans聚类弊端示意图&lt;/center&gt;&#xA;&lt;p&gt;通过上面这个例子可以知道，初始簇中心的位置会严重影响Kmeans聚类算法的最终结果。对于这种情况，该怎样在最大程度上避免呢？此时就要轮到Kmeans++算法出场了。&lt;/p&gt;&#xA;&lt;p&gt;从整体上看Kmeans++聚类算法同Kmeans聚类算法一致，唯一的区别在于初始簇中心的选择上。在Kmeans++聚类算法中，对于初始簇中心的选择是逐一进行的，并且每次在选择当前簇中心时都会选择离已有簇中心尽可能远的样本的作为簇中心，以此来避免所有簇中心出现在同一个簇中的情况。同时，在sklearn中只需要在实例化时指定对应的初始化方法，即&lt;code&gt;KMeans(n_clusters=K,init=&#39;k-means++&#39;)&lt;/code&gt;，便可使用Kmeans++聚类算法，使用示例这里就不再赘述。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1152-kmeans算法原理&#34;&gt;11.5.2 Kmeans++算法原理&lt;a class=&#34;anchor&#34; href=&#34;#1152-kmeans%e7%ae%97%e6%b3%95%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Kmeans++[1]仅从名字也可以看出它是Kmeans聚类算法的改进版。一言以蔽之，Kmeans++算法仅仅在初始化簇中心的方式上做了改进，其他地方同Kmeans聚类算法一样。将Kmeans++在初始化簇中心时的方法总结成一句话就是： 逐个选取K个簇中心，并且离其他簇中心越远的样本点越有可能被选为下一个簇中心。其具体做法如下：&lt;/p&gt;&#xA;&lt;p&gt;(1) 从数据集$X$中随机（均匀分布）选取一个样本点作为第1个初始聚类中心$c_1$。&lt;/p&gt;&#xA;&lt;p&gt;(2) 接着计算每个样本点$x\in X$与当前已有聚类中心之间的最短距离，并用$D(x)$表示，然后计算每个样本点${{x}^{\prime }}\in X$被选为下一个聚类中心的概率，并选择最大概率值所对应的样本点作为下一个簇中心$c_i$。&#xA;&lt;/p&gt;&#xA;$$&#xA;{{c}_{i}}=\underset{{{x}^{\prime }}}{\mathop{\arg \max }}\,\frac{D{{({{x}^{\prime }})}^{2}}}{\sum\limits_{x\in X}{D}{{(x)}^{2}}}\tag{11-6}&#xA;$$&lt;h2 id=&#34;1153-kmeans计算示例&#34;&gt;11.5.3 Kmeans++计算示例&lt;a class=&#34;anchor&#34; href=&#34;#1153-kmeans%e8%ae%a1%e7%ae%97%e7%a4%ba%e4%be%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;h2 id=&#34;1154-从零实现kmeans聚类算法&#34;&gt;11.5.4 从零实现Kmeans++聚类算法&lt;a class=&#34;anchor&#34; href=&#34;#1154-%e4%bb%8e%e9%9b%b6%e5%ae%9e%e7%8e%b0kmeans%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;h2 id=&#34;1155-小结&#34;&gt;11.5.5 小结&lt;a class=&#34;anchor&#34; href=&#34;#1155-%e5%b0%8f%e7%bb%93&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;subscribe&gt;38&lt;/subscribe&gt;&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;</description>
			</item>
			<item>
				<title>11.6 聚类外部评价指标</title>
				<link>https://mlwithme.github.io/ml/chapter11/1ede2f3557d0438f/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/1ede2f3557d0438f/</guid>
				<description>&lt;p&gt;推文介绍：&lt;/p&gt;&#xA;&lt;p&gt;如同之前已经接受过的分类算法一样，对于聚类算法来讲同样也会通过一些评价指标来衡量聚类算法的优与劣。在聚类任务中，常见的评价指标有纯度（Purity）、兰德系数（Rand Index, RI）、F值（Fscore）和调整兰德系数（Adjusted Rand Index,ARI）这4种外部评价指标。本节内容将会详细介绍这4中指标的原理与实现方式，同时订阅本专栏也可阅读更多优质内容。&lt;/p&gt;&#xA;&lt;h1 id=&#34;116-聚类外部评价指标&#34;&gt;11.6 聚类外部评价指标&lt;a class=&#34;anchor&#34; href=&#34;#116-%e8%81%9a%e7%b1%bb%e5%a4%96%e9%83%a8%e8%af%84%e4%bb%b7%e6%8c%87%e6%a0%87&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面几节内容的介绍，相信各位读者对于聚类算法已经有了一定的了解。不过正如之前介绍的分类算法模型一样，对于聚类算法来讲同样也会通过一些评价指标来衡量聚类结果的优与劣。在聚类任务中，常见的评价指标有纯度（Purity）、兰德系数（Rand Index, RI）、F值（Fscore）和调整兰德系数（Adjusted Rand Index, ARI）等。之所以称之为外部评价指标（External metrics），是因为这样的评价指标在计算结果的时候需要依赖样本的真实标签，在11.8节内容中我们还将介绍只依赖于样本本身的评价方法，即内部评价指标。下面，分别来对这4种指标一一进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;假设现在有一批文档，一共包含叉形、圆形与菱形3个类别。此时需要对其进行聚类处理，并且现在某聚类算法的聚类结果如图11-11所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/ml/p10-8.png&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-11 文档聚类结果&lt;/center&gt;&#xA;&lt;p&gt;从图11-11可知，该聚类算法将所有的文本一共划分成了3个簇。面对这样的聚类结果，应该怎样来对其进行评判呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;1161-聚类纯度&#34;&gt;11.6.1 聚类纯度&lt;a class=&#34;anchor&#34; href=&#34;#1161-%e8%81%9a%e7%b1%bb%e7%ba%af%e5%ba%a6&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在聚类结果的评估标准中，一种最简单最直观的方法就是计算它的聚类纯度。别看纯度听起来很陌生，但实际上和分类问题中的准确率有着异曲同工之妙。因为聚类纯度的总体思想也用聚类正确的样本数除以总的样本数，因此它也经常被称为聚类的准确率。只是对于聚类后的结果我们并不知道每个簇所对应的真实类别，因此需要取每种情况下的最大值。具体地，将纯度的计算公式定义为[1]&#xA;&lt;/p&gt;&#xA;$$&#xA;P=(\Omega ,\mathbb{C})=\frac{1}{N}\sum\limits_{k}{\underset{j}{\mathop{\max }}\,}|{{\omega }_{k}}\bigcap {{c}_{j}}|\tag{11-7}&#xA;$$&lt;p&gt;&#xA;其中，$N$表示总的样本数； $\Omega=\{\omega_1,\omega_2,...,\omega_K\}$表每一个聚类后的簇； 而$\mathbb{C}=\{c_1,_2,...c_J\}$表示正确的类别； $\omega _k$表示聚类后第$k$个簇中的所有样本； $c_j$表示第$j$个类别的真实样本数。在这里$P$的取值范围为$[0,1]$，其值越大表示聚类效果越好。&lt;/p&gt;&#xA;&lt;p&gt;有了式(11-7)以后就可以通过它来计算图11-11中聚类结果的纯度。对于第1个簇来讲，$|{{\omega }_{1}}\bigcap {{c}_{1}}|=5$，$|{{\omega }_{1}}\bigcap {{c}_{2}}|=1$，$|{{\omega }_{1}}\bigcap {{c}_{3}}|=0$，可以看出此时假设$c_1$对应的是叉形、$c_2$对应的是圆形、$c_3$对应的是菱形（这个对应顺序没有任何关系），因此第1个簇聚类正确的样本数为5。同理，按照这样的方法可以计算得到第2个簇和第3个簇聚类正确的样本数分别为4和3，所以对于图11-11所示的聚类结果来讲，其最终的纯度为&#xA;&lt;/p&gt;&#xA;$$&#xA;P=\frac{5+4+3}{17}\approx 0.706\tag{11-8}&#xA;$$&lt;h2 id=&#34;1162-兰德系数与值&#34;&gt;11.6.2 兰德系数与$\text{F}$值&lt;a class=&#34;anchor&#34; href=&#34;#1162-%e5%85%b0%e5%be%b7%e7%b3%bb%e6%95%b0%e4%b8%8e%e5%80%bc&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完纯度这一评价指标后，我们再来看一看兰德系数（Rand Index）和$\text{F}$值。虽然兰德系数听起来是一个陌生的名词，但它的计算过程却与准确率的计算过程类似。同时，虽然这里也有一个叫做$\text{F}$值的指标，并且它的计算过程也和分类指标中的$\text{F}$值类似，但是两者却有着本质的差别。讲了这么多，这两个指标到底该怎么算呢？同分类问题中的混淆矩阵类似，这里也要先定义4种情况以便进行计数，然后进行指标的计算。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 计算原理&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;为了说明兰德系数背后的思想，我们这里还是以图11-11中的聚类结果为例进行说明。现在请各位读者想象一下，把这3个簇想象成3个黑色的布袋。对于任意一个布袋来讲： ①如果从里面任取两个样本均是同一个类别，这就表示这个布袋中的所有样本都算作是聚类正确的。②相反，如果取出来后发现存在两个样本不是同一类别的情况，则说明存在着聚类错误的情况。&lt;/p&gt;&#xA;&lt;p&gt;其次，对于任意两个布袋来讲。③如果任意从两个布袋中各取一个样本后发现两者均是不同类别的，这就表示两个布袋中的样本都被聚类正确了。④相反，如果发现取出来的两个样本存在相同的情况，则说明此时也存在着聚类错误的情况。各位读者想一想，此时应该再也找不出第5种情况了。由此，可以做出如下定义。&lt;/p&gt;&#xA;&lt;p&gt;TP： 表示两个同类样本点在同一个簇（布袋）中的情况数量，即同簇同类的样本对。&lt;/p&gt;&#xA;&lt;p&gt;FP： 表示两个非同类样本点在同一个簇中的情况数量，同簇异类的样本对。&lt;/p&gt;&#xA;&lt;p&gt;TN： 表示两个非同类样本点分别在两个簇中的情况数量，即异簇异类的样本对。&lt;/p&gt;&#xA;&lt;p&gt;FN： 表示两个同类样本点分别在两个簇中的情况数量，即异簇同类的样本对。&lt;/p&gt;&#xA;&lt;p&gt;由此，根据图11-11所示的聚类结果便可以得到如表11-3所示的对混淆矩阵（Pair Confusion Matrix）。&lt;/p&gt;&#xA;&lt;center&gt;表 11-3 对混淆矩阵&lt;/center&gt;&lt;div align=center&gt;&lt;img width=&#34;600&#34; src=&#34;https://mlwithme.github.io/images/ml/t10-3.jpg&#34;/&gt;&lt;/div&gt;&#xA;&lt;p&gt;其中表11-3里&lt;code&gt;TP=20&lt;/code&gt;的含义是在所有簇的任一簇中任取两个样本均是同一类别的情况总数。&lt;code&gt;TN=72&lt;/code&gt;则表示在所有簇的任两簇中各取一个样本均不是同一类别的情况总数。&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.7 加权Kmeans聚类算法</title>
				<link>https://mlwithme.github.io/ml/chapter11/e6a75df19f85498c/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/e6a75df19f85498c/</guid>
				<description>&lt;p&gt;推文介绍：&lt;/p&gt;&#xA;&lt;p&gt;想象一下这样一个场景，假设现在手中有一个数据集，里面包含3个特征维度，但是，对于簇结构起决定性作用的只有其中2个维度，也就是说其中有一个维度是噪声维度。在这种情况下采用Kmeans聚类算法进行聚类会产生什么样的结果呢？此时我们便需要一种聚类算法能够自动帮我们识别哪些维度是噪音维度。在本节内容中将会介绍一种基于加权的Kmeans聚类算法原理与实现。&lt;/p&gt;&#xA;&lt;h1 id=&#34;117-加权kmeans聚类算法&#34;&gt;11.7 加权Kmeans聚类算法&lt;a class=&#34;anchor&#34; href=&#34;#117-%e5%8a%a0%e6%9d%83kmeans%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中，我们首先介绍了Kmeans聚类算法的原理，然后介绍了一种基于Kmeans进行改进的Kmeans++聚类算法，该算法的改进点在于依次初始化K个簇中心，最大程度上使不同的簇中心彼此之间相距较远，从而避免了各个簇中心出现在同一簇中的情况。接下来，我们将继续介绍另外一种基于Kmeans改进的聚类算法——加权Kmeans聚类算法。如图11-13所示便是加权Kmeans聚类算法的学习路线图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/ml/240427160043.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 11-13 加权Kmeans聚类算法学习路线图&lt;/center&gt;&#xA;&lt;h2 id=&#34;1171-加权kmeans算法思想&#34;&gt;11.7.1 加权Kmeans算法思想&lt;a class=&#34;anchor&#34; href=&#34;#1171-%e5%8a%a0%e6%9d%83kmeans%e7%ae%97%e6%b3%95%e6%80%9d%e6%83%b3&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;想象一下这样一个场景，假设现在手中有一个数据集，里面包含3个特征维度，但是，对于簇结构起决定性作用的只有其中2个维度，也就是说其中有一个维度是噪声维度。在这种情况下采用Kmeans聚类算法进行聚类会产生什么样的结果呢？&lt;/p&gt;&#xA;&lt;p&gt;现在我们人为地来构造一个数据集，其一共包含3个明显的簇结构，可视化后的结果如图11-14所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/ml/p10-10.png&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-14 不含有噪声维度的样本&lt;/center&gt;&#xA;&lt;p&gt;进一步，在图11-14所示的数据集中再加入一个噪声维度，这样便得到了另外一个新的数据集，其可视化结果如图11-15所示，其中左右两边为不同视角下的结果。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;600&#34; src=&#34;https://mlwithme.github.io/images/ml/p10-11.png&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-15 含有噪声维度的样本&lt;/center&gt;&#xA;&lt;p&gt;此时，对于图11-15中的结果，人眼几乎已经无法分辨其中所存在的簇结构。如果此时通过聚类对其进行聚类会出现什么样的结果呢？在通过Kmeans算法对其进行聚类后发现，此时的ARI结果已经从0.912骤然降到了0.721，完整示例代码可参见AllBooKCode/Chapter11/C09_visualization_wkmeans.py文件。为什么混入噪声维度后Kmeans聚类算法就不怎么管用了呢？&lt;/p&gt;&#xA;&lt;p&gt;假如现在有两个簇中心$c_1=[2,3]$和$c_2=[3,5]$，样本点$x=[4,4]$。在这种情况下$d_{x{{c}_{1}}}^{2}=5$大于$d_{x{{c}_{2}}}^{2}=2$，因此样本点$x$应该被划入簇$c_2$中，但如果此时加入一列噪声维度，变成$c_1=[2,3,2]$和$c_2=[3,5,9]$，样本点变成$x=[4,4,1]$。那么在这样的情况下$d_{x{{c}_{1}}}^{2}=6$就会小于$d_{x{{c}_{2}}}^{2}=66$，此时$x$就会被错误地划分到簇$c_1$中。&lt;/p&gt;&#xA;&lt;p&gt;可以发现，正是由于噪声维度的出现，使得Kmeans聚类算法在计算样本间的距离时把噪声维度所在的距离也一并地考虑到了结果中，最终导致聚类精度下降。有没有什么好的办法解决这个问题，使在聚类过程中尽量忽略噪声维度的影响呢？当然有，答案就是给每个特征维度赋予一个权重。&lt;/p&gt;&#xA;&lt;p&gt;加权Kmeans聚类算法出自于2005年的一篇论文[1] 。这篇论文的核心思想就是给每个特征维度初始化一个权重值，等到目标函数收敛时噪声维度所对应的权重就会趋于0，从而使在计算样本间的距离时能够尽可能地忽略噪声维度的影响。&lt;/p&gt;&#xA;&lt;p&gt;在上面的例子中，如果给算法&lt;/p&gt;&#xA;$$W=[w_1,w_2,w_3]=[0.49,0.49,0.02]$$&lt;p&gt;这样一个特征权重，并且在计算样本间距离的时候考虑的是加权距离，则有&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;  &amp; d_{x{{c}_{1}}}^{2}=0.49\times {{(4-2)}^{2}}+0.49\times {{(4-3)}^{2}}+0.02\times {{(1-2)}^{2}}=2.47 \\[1ex] &#xA; &amp; d_{x{{c}_{2}}}^{2}=0.49\times {{(4-3)}^{2}}+0.49\times {{(4-5)}^{2}}+0.02\times {{(1-9)}^{2}}=2.26 &#xA;\end{aligned}\tag{11-28}&#xA;$$&lt;p&gt;&#xA;此时可以发现，在特征权重的作用下，加权后的距离$d^2_{xc_1}$仍旧大于$d^2_{xc_2}$，$x$依然会被划分到簇$c_2$中，因此也就避免了被划分错误的情况。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1172-加权kmeans算法原理&#34;&gt;11.7.2 加权Kmeans算法原理&lt;a class=&#34;anchor&#34; href=&#34;#1172-%e5%8a%a0%e6%9d%83kmeans%e7%ae%97%e6%b3%95%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;讲了这么多，那么加权Kmeans聚类算法是如何实现这个想法的呢？具体地，加权Kmeans聚类算法的目标函数为&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;&amp;P(U,Z,W)=\sum\limits_{p=1}^{k}{\sum\limits_{i=1}^{n}{{{u}_{ip}}}}\sum\limits_{j=1}^{m}{w_{j}^{\beta }}{{({{x}_{ij}}-{{z}_{pj}})}^{2}}\\[2ex]&#xA;&amp;\text{s}.\text{t}. \ \sum\limits_{p=1}^{k}{{{u}_{ip}}}=1,\ \sum\limits_{j=1}^{m}{{{w}_{j}}}=1&#xA;\end{aligned}&#xA;\tag{11-29}&#xA;$$&lt;p&gt;&#xA;从目标函数式(11-29)可以发现，相较于原始的Kmeans聚类算法，加权Kmeans聚类算法仅仅在目标函数中增加了一个权重参数$w^{\beta}_j$。它的作用在于，在最小化整个簇内距离时计算的是每个维度的加权距离和，即通过不同的权重值来调节每个维度对聚类结果的影响，并且，当$\beta=0$时，目标函数式(11-29)也就退化到了Kmeans聚类算法中的目标函数。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1173-加权kmeans算法迭代公式&#34;&gt;11.7.3 加权Kmeans算法迭代公式&lt;a class=&#34;anchor&#34; href=&#34;#1173-%e5%8a%a0%e6%9d%83kmeans%e7%ae%97%e6%b3%95%e8%bf%ad%e4%bb%a3%e5%85%ac%e5%bc%8f&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据目标函数式(11-29)可知，其一共包含3个需要求解的参数$U$、$Z$和$W$。在这里，我们先直接给出每个参数的迭代计算公式，具体的求解过程将在11.7.4节中进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 簇分配矩阵$U$&lt;/strong&gt;&lt;/p&gt;&#xA;$$&#xA;{{u}_{ip}}=\begin{cases}&#xA;   1, &amp; w_{j}^{\beta }\sum\limits_{j=1}^{m}{{{({{x}_{ij}}-{{z}_{pj}})}^{2}}}\le w_{j}^{\beta }\sum\limits_{j=1}^{m}{{{({{x}_{ij}}-{{z}_{tj}})}^{2}}},\ \text{for }1\le t\le k  \\&#xA;   0, &amp; \text{其它}  \\&#xA;\end{cases} \tag{11-30}&#xA;$$&lt;p&gt;从式(11-30)可以看出，其与Kmeans中簇分配矩阵计算方式的差别在于每个维度在计算距离时考虑了权重。&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.8 聚类内部评价指标</title>
				<link>https://mlwithme.github.io/ml/chapter11/c52cf7920f1d4636/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/c52cf7920f1d4636/</guid>
				<description>&lt;h1 id=&#34;118-聚类内部评价指标&#34;&gt;11.8 聚类内部评价指标&lt;a class=&#34;anchor&#34; href=&#34;#118-%e8%81%9a%e7%b1%bb%e5%86%85%e9%83%a8%e8%af%84%e4%bb%b7%e6%8c%87%e6%a0%87&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在第11.6节内容中，我们详细介绍了聚类算法中几种常见的评价指标，包括纯度（准确率）、精确率、召回率、兰德系数和F值等。虽然这些评价指标都能很好的评估聚类结果的优劣，但是它们都有着一个共同的强使用条件，那就是需要知道训练样本的真实标签（Ground Truth），而这在现实情况中却很难做到。&lt;/p&gt;&#xA;&lt;p&gt;对于聚类结果的评价方法一般可以分为内部评价指标（Internal Evaluation）与外部评价指标。所谓外部评价指标是指在知道真实标签的情况下来评估聚类结果的好坏，即上面提到几种评价指标。一般来说在做论文，或者是有少量的标注数据时，都可以用外部评价指标选择一个相对最优的聚类模型，然后再将其应用到其它未被标记的数据中。所谓内部评价指标则是不借助于外部信息，仅仅只是依靠聚类结果和样本本身的属性（空间分布特性等）来进行评估的办法。常见的内部评价指标有轮廓系数（Silhouette Coefficient）、卡林斯基-哈拉巴斯指数（Calinski-Harabasz Index, CHI）和戴维斯-布尔丁指数（Davies-Bouldin Index, DBI）等。在接下来的这节内容中，我们将会分别就这3种常见的内部评价指标进行介绍。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1181-轮廓系数&#34;&gt;11.8.1 轮廓系数&lt;a class=&#34;anchor&#34; href=&#34;#1181-%e8%bd%ae%e5%bb%93%e7%b3%bb%e6%95%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;所谓轮廓系数[1]它本质上衡量的是每个样本点到其簇内样本的距离与其最近簇结构之间距离的比值。如果该比值越小，则说明该样本点所在的簇结构与其最近簇结构之间的距离越远，从而说明此时的聚类结果越好。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 计算原理&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在介绍轮廓系数原理之前，首先需要明白的是对于聚类结果的轮廓系数，它实际上是所有样本点轮廓系数的平均值，也就是说聚类样本中的每个样本点对应都有一个轮廓系数值，而总的轮廓系数则是所有样本点轮廓系数的平均值。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;320&#34; src=&#34;https://mlwithme.github.io/images/ml/22042417328.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-16 轮廓系数原理图&lt;/center&gt;&#xA;&lt;p&gt;如图11-16所示，数据样本中一共包含有3个簇结构，对于最左边这个簇中（圆形）的样本点$i$来说，距离其最近的簇为中间（方形）这个簇。现在定义样本$i$到簇中每个样本距离的均值为$a(i)$，到最近簇中每个样本距离的均值为$b(i)$，即此时根据图11-16所示的结果有&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;a(i) &amp;= \frac{a_1+a_2+a_3+a_4}{4}\\[2ex]&#xA;b(i) &amp;=\frac{b_1+b_2+b_3+b_4}{4}&#xA;\end{aligned}\tag{11-40}&#xA;$$&lt;p&gt;&#xA;这里需要注意的一点是，对于同一个簇中的每个样本点来说，距离自己最近的簇可能并不是同一个；同时，在寻找距离当前样本点最近的簇结构时，计算的是当前样本点到各个簇中心的最短距离，而不是计算当前样本点所在簇的簇中心到其它每个簇中心的最短距离。&lt;/p&gt;&#xA;&lt;p&gt;此时，样本$i$的轮廓系数$s(i)$定义为&lt;/p&gt;&#xA;$$&#xA;s(i) = &#xA;    \begin{cases}&#xA;        1-a(i)/b(i), &amp; \text{if} \;a(i) &lt; b(i) \\[2ex]&#xA;        0,        &amp; \text{if} \;a(i) = b(i) \\[2ex]&#xA;        b(i)/a(i)-1 &amp; \text{if} \;a(i) &gt; b(i)&#xA;    \end{cases}\tag{11-41}&#xA;$$&lt;p&gt;从式(11-41)可以看出，当$a(i)$越小而$b(i)$越大时，此时对应的情况是样本$i$所在的簇中所有样本点之间距离都比较近（簇内距离较小），样本$i$所在的簇距离其最近簇的距离较远（因为此时样本$i$所在的簇中簇内距离较小，所以样本$i$到其它簇的距离可以近似地看做样本$i$所在簇到其它簇之间的距离），所以$s(i)$此时也就越接近于1，即聚类效果越好。&lt;/p&gt;&#xA;&lt;p&gt;类似地，当$b(i)$越小而$a(i)$越大时，此时对应的情况是样本$i$所在的簇中所有样本点之间距离都比较远（簇内距离较大），样本$i$所在的簇距离其最近簇的距离较近，所以$s(i)$此时也就越接近于-1，即聚类效果越差。&lt;/p&gt;&#xA;&lt;p&gt;最后，当样本$i$所在的簇中只有样本$i$一个样本时，那么对于样本$i$到底属于哪个簇就变得不清楚了，此时可以粗略地认为属于离它最近的簇中，所以此时有$a(i) = b(i)$，即$s(i)=0$表示一种中立的情况。&lt;/p&gt;&#xA;&lt;p&gt;由此可知$s(i)$的取值范围应该是$-1\leq s(i)\leq 1$，且进一步式(11-41)可以改为&#xA;&lt;/p&gt;&#xA;$$&#xA;s(i)=\frac{b(i)-a(i)}{\max\{a(i),b(i)\}}\tag{11-42}&#xA;$$&lt;p&gt;&#xA;最终，整个聚类结果的轮廓系数结果为&#xA;&lt;/p&gt;&#xA;$$&#xA;s=\frac{1}{n}\sum_{i=1}^ns(i)\tag{11-43}&#xA;$$&lt;p&gt;&#xA;其中$n$表示样本点的个数。&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.9 聚类K值选取与分析</title>
				<link>https://mlwithme.github.io/ml/chapter11/f95259c359b146ba/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/f95259c359b146ba/</guid>
				<description>&lt;h1 id=&#34;119-聚类k值选取与分析&#34;&gt;11.9 聚类K值选取与分析&lt;a class=&#34;anchor&#34; href=&#34;#119-%e8%81%9a%e7%b1%bbk%e5%80%bc%e9%80%89%e5%8f%96%e4%b8%8e%e5%88%86%e6%9e%90&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中，我们陆续介绍了3种常见的聚类算法原理及其实现 、4种常见的聚类外部评价指标和3种常见的聚类内部评价指标，对于聚类算法的主体内容算是介绍得差不多了，但是还遗留了最后一个问题——K值的选取。通常来说在实际场景中数据集的标签都是未知的，相反恰好需要通过聚类结果来辅助将各个簇的样本区分开。那到底应该如何选取K值呢？&lt;/p&gt;&#xA;&lt;p&gt;经过上一节内容的介绍，有读者可能会说，以不同的K值为超参数，以某种内部评价指标为标准，通过交叉验证来选择最佳K值不就行了吗？虽然这种想法看起来有道理，但实际上却行不通。以轮廓系数为例，根据轮廓系数的原理可知我们并不能够严格得出在最佳K值的情况下轮廓系数同样也能够取得最大值。因此，我们常常就需要借助一些其它手段来对K值进行分析。&lt;/p&gt;&#xA;&lt;p&gt;在聚类分析中，有两种常见的方法用于K值的选择，分别是肘部法和轮廓系数法，下面分别逐一进行介绍。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1191-k值分析肘部法原理&#34;&gt;11.9.1 K值分析肘部法原理&lt;a class=&#34;anchor&#34; href=&#34;#1191-k%e5%80%bc%e5%88%86%e6%9e%90%e8%82%98%e9%83%a8%e6%b3%95%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据11.1节内容的介绍我们知道，基于Kmeans聚类框架下的聚类算法在最小化目标函数时本质上就是最小化整个簇内距离。根据簇内距离的定义可知，当K值越小时那么簇内距离便会越大；而当K值越大时那么簇内距离便会越小，极端一点在K值等于样本数量时，那么此时的簇内距离可以取到最小值0。&lt;/p&gt;&#xA;&lt;p&gt;进一步，根据分析可知，在K值由小变大的过程中，随着K值的增大簇内距离便会逐步减小，但是当K值取得最优解后簇内距离便不会出现明显的降幅。此时可以想象这么一个场景，假设某数据集以不同的K值进行聚类处理并同时计算得到对应的簇内距离和，再以不同的K值为横坐标，簇内距离为纵坐标进行可视化，便可以得到类似如图11-19所示的结果。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/ml/22050119253.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-19 肘部法原理图&lt;/center&gt;&#xA;&lt;p&gt;如图11-19所示，可以发现刚开始随着K值的增大簇内距离开始急剧减小，当K值大于4之后簇内距离的减少幅度便开始明显降低，因此便可以经验性地得出4是该数据集对应K值的最优解。之所以可以凭借这样的经验进行判断是因为，当K值小于最优解时K值每增加1也就代表多了1个簇结构，整个簇内距离和自然会得到大幅下降；而当K值大于最优解之后K值每增加1也就仅仅只是将原本一个正常的簇结构一分为二了，因此即便整个簇内距离和有所降低，但是幅度也不会太大。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的经验性准则便可以根据类似图11-19中的方法来进行K值的选取。同时，由于图11-19中的变化曲线类似于我们手臂的肘部，因此该方法被称之为肘部法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1192-k值分析肘部法实现&#34;&gt;11.9.2 K值分析肘部法实现&lt;a class=&#34;anchor&#34; href=&#34;#1192-k%e5%80%bc%e5%88%86%e6%9e%90%e8%82%98%e9%83%a8%e6%b3%95%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完肘部法的分析原理以后再来看如何实现这一可视化过程，完整示例代码可参见 &lt;code&gt;AllBooKCode/Chapter11/C12_elbow_analysis.py&lt;/code&gt; 文件。这里首先需要定义一个函数来根据聚类结果计算簇内距离和并进行可视化，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;elbow_analysis&lt;/span&gt;(X, range_n_clusters, all_cluster_labels, all_centers):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     all_dist &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; n, n_clusters &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;enumerate&lt;/span&gt;(range_n_clusters):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;         cluster_labels &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; all_cluster_labels[n]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;         centers &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; all_centers[n]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;         dist &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;range&lt;/span&gt;(n_clusters):  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 遍历每一个簇，计算当前簇的簇内距离&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;             x_data &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X[cluster_labels &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; i]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;             tmp &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sum((x_data &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt; centers[i]) &lt;span style=&#34;color:#666&#34;&gt;**&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, axis&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;             dist &lt;span style=&#34;color:#666&#34;&gt;+=&lt;/span&gt; np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sum(np&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sqrt(tmp))  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 累计当前聚类结果下所有簇的簇内距离和&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;11&lt;/span&gt;         all_dist&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;append(dist)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;12&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;plot(range_n_clusters, all_dist)  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 绘制肘部曲线&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;scatter(range_n_clusters, all_dist)  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 绘制各个点&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;15&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;range&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;len&lt;/span&gt;(range_n_clusters)):  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 在图上进行K值标记&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;16&lt;/span&gt;         plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;annotate(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;k = &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;range_n_clusters[i]&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;                      xy&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;(range_n_clusters[i], all_dist[i]), fontsize&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;18&lt;/span&gt;                      xytext&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;(range_n_clusters[i] &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0.1&lt;/span&gt;, all_dist[i]))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;19&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;xlim(range_n_clusters[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0.5&lt;/span&gt;, range_n_clusters[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0.8&lt;/span&gt;)  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 调整范围&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;20&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;ylim(all_dist[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0.9&lt;/span&gt;, all_dist[&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; all_dist[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0.1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;21&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;yticks([])  &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 去掉y轴上的刻度显示&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;22&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;xlabel(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;K&amp;#34;&lt;/span&gt;, fontsize&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;23&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;ylabel(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;distance&amp;#34;&lt;/span&gt;, fontsize&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;24&lt;/span&gt;     plt&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;show()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第1行&lt;code&gt;X&lt;/code&gt;表示原始的训练样本为一个&lt;code&gt; [n_samples, n_features]&lt;/code&gt;的二维矩阵；&lt;code&gt;range_n_clusters&lt;/code&gt;是K值的取值范围，为一个普通的列表；&lt;code&gt;all_cluster_labels&lt;/code&gt;是一个普通列表，每个元素为一个一维向量，即某一K值下的聚类标签；&lt;code&gt;all_centers&lt;/code&gt;也是一个普通的列表，每个元素为一个&lt;code&gt;[n_clusters,n_features]&lt;/code&gt;的二维矩阵，即某一K值下的聚类簇中心。第3~5行开始遍历不同的K取值，并取对应的聚类结果和聚类簇中心。第7~10行是遍历每一个簇并累加得到所有簇的簇内距离和。第12~13行是对计算得到的结果进行可视化。第15~18行是在图中进行标记。第20~24行是调整坐标轴范围等。&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.10 基于密度的聚类算法</title>
				<link>https://mlwithme.github.io/ml/chapter11/b85c1a858f7c4686/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/b85c1a858f7c4686/</guid>
				<description>&lt;h1 id=&#34;1110-基于密度的聚类算法&#34;&gt;11.10 基于密度的聚类算法&lt;a class=&#34;anchor&#34; href=&#34;#1110-%e5%9f%ba%e4%ba%8e%e5%af%86%e5%ba%a6%e7%9a%84%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中，我们陆续介绍了3种常见聚类算法的原理与实现过程，包括原始的Kmeans聚类算法、Kmeans++聚类算法以及基于特征权重的加权Kmeans聚类算法 ，并且这3种都算是基于Kmeans框架下的聚类算法，也就是说它们本质上解决的都是一类数据的聚类问题。在本节内容中，我们将开始介绍一种新的聚类算法，即基于密度的聚类算法，其学习路线如图11-23所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/ml/240427160551.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 11-23 基于密度的聚类算法学习路线&lt;/center&gt;&#xA;&lt;h2 id=&#34;11101-dbscan算法思想&#34;&gt;11.10.1 DBSCAN算法思想&lt;a class=&#34;anchor&#34; href=&#34;#11101-dbscan%e7%ae%97%e6%b3%95%e6%80%9d%e6%83%b3&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;由于在实际场景中我们遇到的不仅仅只有图11-2所示簇结构的数据集，还可能存在一些其它簇结构形式的数据，例如图11-24所示的结构类型。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/ml/22050420884.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-24 异形数据集&lt;/center&gt;&#xA;&lt;p&gt;如图11-24所示，对于这两种异形的数据集来说，不管是采用前面介绍的3种聚类算法中的哪一种，最后得到的结果都会很差，因为类Kmeans聚类算法都不适合对这种数据进行聚类处理，并且如果一定要用类Kmeans聚类算法来进行聚类，那么将会得到如图11-25所示的结果。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/ml/22050408396.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-25 异形数据集K-means聚类结果&lt;/center&gt;&#xA;&lt;p&gt;如图11-25所示，左右两边均是采用Kmeans++算法聚类后的结果，其中不同颜色表示聚类算法给出的聚类结果，可以看到由于类Kmeans聚类算法的特性，其在这类数据集上的表现并不好。对于图11-25所示这样结构的数据，一种更好的办法是基于密度来进行聚类。&lt;/p&gt;&#xA;&lt;p&gt;基于密度的聚类算法（Density Based Spatial Clustering of Applications with Noise, DBSCAN），1996年由Martin Ester等人提出[1] [2]，它的核心思想是根据样本之间的密度（紧凑程度）来对样本进行聚类处理。例如对于图11-25中所示的两种异形数据来说，两种类别之间有着明显空白之处（密度小），而对于各类别内部的样本来说样本之间分布却非常紧凑（密度大），因此只需要将所有各自相互紧邻的样本点划分为不同的簇结构即可完成整个聚类过程。可以发现，基于这样的聚类思想不管待聚类的数据集是什么样的分布形式，都可以很好的对其进行聚类处理。同时，从算法的全称可以看出，DBSCAN算法的原理除了是基于密度这一特性外，它还能有效地发掘数据中的异常样本，即那些密度低且相对孤立的样本点。&lt;/p&gt;&#xA;&lt;h2 id=&#34;11102-dbscan示例代码&#34;&gt;11.10.2 DBSCAN示例代码&lt;a class=&#34;anchor&#34; href=&#34;#11102-dbscan%e7%a4%ba%e4%be%8b%e4%bb%a3%e7%a0%81&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完DBSCAN算法的思想以后，我们再来看如何借助sklearn来完成整个建模过程，完整示例代码可参见 &lt;code&gt;AllBooKCode/Chapter11/C17_dbscan_train.py&lt;/code&gt; 文件。具体地，先构造类似图11-25所示的数据集，然后使用sklearn中的DBSCAN模块来完成整个聚类过程，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;sklearn.cluster&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; DBSCAN&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;sklearn.datasets&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; make_moons&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#bb60d5&#34;&gt;__name__&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     X, y &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; make_moons(n_samples&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;700&lt;/span&gt;, noise&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.05&lt;/span&gt;, random_state&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2020&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     X &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; StandardScaler()&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;fit_transform(X)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;     db &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; DBSCAN(eps&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.3&lt;/span&gt;, min_samples&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;     db&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;fit(X)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;调整兰德系数为: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;adjusted_rand_score(y, db&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;labels_)&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第1行是导入基于密度的聚类模块。第2行是导入一个函数，并通过第5行所示的方式来构造形如图11-25右边所示数据集。第6行是对数据样本进行标准化处理。第7行是利用DDBSCAN聚类算法对样本进行聚类处理，其中&lt;code&gt;eps&lt;/code&gt;和&lt;code&gt;min_samples&lt;/code&gt;表示用于构建核心样本的两个关键参数，&lt;code&gt;eps&lt;/code&gt;越大且&lt;code&gt;min_samples&lt;/code&gt;越小则最终得到的簇结构将会偏少，反之则得到簇结构将会偏多，详细原理见下文。第8~9行则是对于样本进行聚类处理，并通过调整兰德系数来对聚类结果进行评估。&lt;/p&gt;&#xA;&lt;h2 id=&#34;11103-dbscan算法核心概念&#34;&gt;11.10.3 DBSCAN算法核心概念&lt;a class=&#34;anchor&#34; href=&#34;#11103-dbscan%e7%ae%97%e6%b3%95%e6%a0%b8%e5%bf%83%e6%a6%82%e5%bf%b5&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在正式介绍DBSCAN算法的原理之前，先来介绍算法中几个非常重要的核心概念，核心样本、直接可达、可达和异常样本。同时，在DBSCAN算法中还有两个非常关键的超参数，半径$r$和最小样本数$\text{minPts}$，如图11-26所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;180&#34; src=&#34;https://mlwithme.github.io/images/ml/22050558061.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-26 核心样本原理图&lt;/center&gt;&#xA;&lt;p&gt;1）核心样本（Core Point）：以样本点$p$为圆心$r$为半径作圆，如果圆域内至少存在$\text{minPts}$个样本（包括$p$自身），则称$p$为核心样本，否则称为非核心样本（Non-core Point）。&lt;/p&gt;&#xA;&lt;p&gt;2）直接可达（Directly Reachable ）：以核心样本$p$为圆心$r$为半径，圆域内的所有样本点对于$p$来说直接可达。&lt;/p&gt;</description>
			</item>
			<item>
				<title>11.11 基于层次的聚类算法</title>
				<link>https://mlwithme.github.io/ml/chapter11/2f01ba751d914336/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/ml/chapter11/2f01ba751d914336/</guid>
				<description>&lt;h1 id=&#34;1111-基于层次的聚类算法&#34;&gt;11.11 基于层次的聚类算法&lt;a class=&#34;anchor&#34; href=&#34;#1111-%e5%9f%ba%e4%ba%8e%e5%b1%82%e6%ac%a1%e7%9a%84%e8%81%9a%e7%b1%bb%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;经过前面几节内容的介绍，我们已经清楚了Kmeans、Kmeans++、基于权重的加权Kmeans和DBSCAN这4种聚类算法的原理与实现。总的来说这4种聚类算法各有千秋，分别都能在一些独特的场景中发挥自己的优势。在接下来的这篇文章中，我们将会为大家介绍第5种常见的聚类算法，层次聚类算法（Hierarchical Clustering），如图11-30所示便是整个算法的学习路线图。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/ml/240427161413.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 11-30 层次聚类算法学习路线图&lt;/center&gt;&#xA;&lt;h2 id=&#34;11111-hca算法思想&#34;&gt;11.11.1 HCA算法思想&lt;a class=&#34;anchor&#34; href=&#34;#11111-hca%e7%ae%97%e6%b3%95%e6%80%9d%e6%83%b3&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;现在想象这么一个场景，假如你有大量病人的就医资料，需要通过聚类将其划分为不同的科室，例如消化科、呼吸科和皮肤科等等。但是除此之外，你还想顺便得到每个科室下具体病症的情况，例如呼吸科下面可能有肺炎病人、普通感冒病人等等。如果是通过前面介绍的4种聚类算法来进行建模，那么显然只能得到以科室为颗粒度的聚类结果[1]。&lt;/p&gt;&#xA;&lt;p&gt;不过此时有读者可能会说，直接以病症为颗粒度进行聚类不就解决了吗？虽然理论上可以这么做，但是这种做法的弊端在于K值太大聚类结果可能不会太理想。同时，在其它我们不知道样本的层次结构中（假如在上面例子中不知道肺炎和感冒属于呼吸科），还能够通过层次聚类算法来发现这种潜在的结构。&lt;/p&gt;&#xA;&lt;p&gt;在数据挖掘和统计分析中，层次聚类也叫做层次聚类分析（Hierarchical Cluster Analysis, HCA），旨在得到样本簇结构的同时发现样本分布的层次结构[2]。同时，层次聚类算法一般来说可以分为两种，一种是自下而上（Bottom-up）的凝聚层次聚类（Agglomerative Clustering）和自上而下的分裂层次聚类（Divisive Clustering）。&lt;/p&gt;&#xA;&lt;p&gt;凝聚层次聚类算法在聚类伊始会将数据中的每个样本点均看作是一个独立的簇结构，然后迭代将当前状态下最相似的两个簇进行合并，直到最后只剩下一个簇时聚类结束。对于分裂层次聚类算法来说则恰恰相反，分裂层次聚类算法在聚类伊始将所有的样本点都看成是一个簇，然后迭代将当前状态下最大的簇划分为两部分，直到最后将整个数据集划分成$n$个簇结束[2]。&lt;/p&gt;&#xA;&lt;p&gt;由于在实际应用中基于自上而下的分裂层次聚类使用较少，所以后续将只介绍采用不同策略下的凝聚层次聚类算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;11112-hca示例代码&#34;&gt;11.11.2 HCA示例代码&lt;a class=&#34;anchor&#34; href=&#34;#11112-hca%e7%a4%ba%e4%be%8b%e4%bb%a3%e7%a0%81&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完层次聚类算法的基本思想以后，再来看如何借助sklearn来完成整个层次聚类的建模过程，以下完整示例代码可参见 &lt;code&gt;AllBooKCode/Chapter11/C19_hca_train.py&lt;/code&gt; 文件，示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;sklearn.cluster&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; AgglomerativeClustering&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#bb60d5&#34;&gt;__name__&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     n_clusters &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     X, y &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; load_iris(return_X_y&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     X &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; StandardScaler()&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;fit_transform(X)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;     model &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; AgglomerativeClustering(n_clusters&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;n_clusters, linkage&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;ward&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;     model&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;fit(X)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;兰德系数为: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;adjusted_rand_score(y, model&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;labels_)&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第1行代码便是导入sklearn中的凝聚层次聚类算法模块。第4~6行是导入数据集并进行标准化处理。第7行是实例化一个类对象，其中&lt;code&gt;linkage&lt;/code&gt;参数表示指定一种层次聚类的算法，取值有&lt;code&gt;&#39;ward&#39;&lt;/code&gt;、&lt;code&gt; &#39;complete&#39;&lt;/code&gt;和 &lt;code&gt;&#39;single&#39;&lt;/code&gt;这3种，后续也将分别详细进行介绍。第8~9行是先完成整个聚类过程，然后对聚类结果进行评估。&lt;/p&gt;&#xA;&lt;h2 id=&#34;11113-hca算法原理&#34;&gt;11.11.3 HCA算法原理&lt;a class=&#34;anchor&#34; href=&#34;#11113-hca%e7%ae%97%e6%b3%95%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在知道了层次聚类算法的基本思想后再来看聚类过程的具体步骤。根据上面的介绍，可以将整个聚类过程归结为如下3步：&lt;/p&gt;&#xA;&lt;p&gt;（1）将每个样本点均初始化为一个单独的簇；&lt;/p&gt;&#xA;&lt;p&gt;（2）如果当前只存在一个簇则进入第（3）步，否则寻找当前状态下最相似的两个簇进行合并；&lt;/p&gt;&#xA;&lt;p&gt;（3）返回整个聚类合并结果[1]。&lt;/p&gt;&#xA;&lt;p&gt;如图11-31所示从$a$到$j$一共有10个样本点，下面将按照上述3个步骤来对凝聚层次聚类算法的聚类过程进行示例。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/ml/22051527824.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 11-31 层次聚类算法原理图&lt;/center&gt;&#xA;&lt;p&gt;如图11-31右侧所示，首先将这10个样本点均看作是一个单独的簇结构$(\cdot )$；其次假定此时在所有簇的两两组合中，$(g)$和$(h)$这两个簇最相似，那么则将其合并为一个簇$(g,h)$；由于此时不止一个簇所以继续迭代，将$(i)$和$(j)$这两个簇进行合并得到簇$(i,j)$；进一步，根据同样的方式将会得到簇$(e,f)$；同理，再次将$(g,h)$与$(i,j)$合并得到簇$((g,h),(i,j))$；将$(b)$和$(c)$合并得到簇$(b,c)$；将$(d)$和$(e,f)$合并得到簇$(d,(e,f))$；将$(b,c)$和$(d,(e,f))$合并得到$((b,c),(d,(e,f)))$；将$(a)$与$((b,c),(d,(e,f)))$合并得到簇$(a,((b,c),(d,(e,f))))$；最后，将$((g,h),(i,j))$和$(a,((b,c),(d,(e,f))))$合并得到簇$(((g,h),(i,j)),(a,((b,c),(d,(e,f)))))$。由于此时只剩下一个簇，所以层次聚类过程结束。与此同时，我们还可以通过图11-31左侧所示的树状图（Dendrogram）来观察每个簇内部层次结构。&lt;/p&gt;&#xA;&lt;p&gt;介绍到这里肯定有读者会问，既然凝聚层次聚类算法的终止条件是只剩下一个簇，那么聚类结束后的簇结构到是怎么样的呢？如图11-31左侧所示，在整个聚类过程中，如果不进行最后1次合并那么将会得到两个簇结构；如果在倒数第2次停止合并那么将会得到3个簇结构，以此类推。同时，在每个簇的内部还能看到剩余样本的层次结构。因此实际情况中，如果我们知道真实的簇数量K，那么完全可以在只剩下K个簇的时候停止合并，后续的代码实现也将遵循这一准则。&lt;/p&gt;&#xA;&lt;p&gt;经过上面的介绍我们发现，凝聚层次聚类算法有两个关键的要素：距离的计算方式和相似性的计算方式（Linkage Criteria）。这一点就类似于K近邻算法一样，也需要两个关键的要素（距离度量方式和决策规则）。因为采用不同的距离计算方式，在后续进行相似性计算时将会得到不同的划分结果。通常在凝聚层次聚类中，距离的度量方式有欧式距离、曼哈顿距离等。对于相似性的度量方式来说常用的有Single-Link、Complete-Link和Ward等[2]。在接下来的内容，我们将分别介绍这3种相似性度量方式的原理及实现过程。&lt;/p&gt;&#xA;&lt;h2 id=&#34;11114-single-link算法原理&#34;&gt;11.11.4 Single-Link算法原理&lt;a class=&#34;anchor&#34; href=&#34;#11114-single-link%e7%ae%97%e6%b3%95%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;使用Single-Link作为相似性衡量标准的凝聚层次聚类算法也被称之为最近邻聚类（Nearest Neighbour Clustering），其核心思想是根据两个簇之间相邻最近两个样本点的距离来作为相似性评判标准，距离越近则表示这两个簇越相似，即这两个簇越有可能被合并。&lt;/p&gt;&#xA;&lt;p&gt;如图11-32所示，在聚类过程中对于任意两个簇结构来说，我们需要计算得到相邻两个簇最近样本点之间的距离作为这两个簇相似性的度量值；然后在所有结果中选择相似度最大的值（距离最小）对应的两个簇进行合并；最后按照同样的方法继续进行迭代直到剩余簇数量为1或到达指定值时结束[1]。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
