无监督学习的简述

Unsupervised Learning[无监督学习]

Clustering[聚类]

Unsupervised Learning: Introduction[无监督学习:介绍]

现在让我们来看看无监督学习。

那么,不知道大家还是否记得在我们最开始的时候是怎么定义无监督学习的么?

我们这里看到的是一个典型的监督学习的例子,我们有一个有标签的训练集,而我们的目标是找到能够区分正样本和负样本的决策边界[画蓝色决策边界]。所以,在监督学习中,我们需要根据这些标注了的数据来拟合一个假设函数。而无监督学习则与此不同,我们的数据是没有标签的。

无监督学习中,我们的数据可能就是这个样子的。我们这里有一些数据点,但它们都没有标签。因此,我们的训练集可以写成这样[下面蓝箭头],只有x(1), x(2),x(3)…,而没有任何标注信息y。所以,在图中,我们的点都是同样的颜色,因为没有标签表明它们是不同的类别。也就是说,在无监督学习中,我们需要对这些无标签的训练数据要做的是,把它们输入到一个算法中,然后我们要求这个算法:帮我们在这个数据集中找到它的内在结构。

比如,对于我们这里展示的这个样例数据集,我们可能需要某种算法帮助我们自动地发现,这个数据集可能是有两个簇。那么这种能够帮助我们从无标注的数据中发现这种类簇的算法,我们称之为聚类算法,英文术语叫做clustering。而这将是我们将要介绍的第一个无监督学习算法。

虽然,也存在其他类型的无监督学习算法,不过不同的无监督学习算法面向的问题可能不太一样,它们可能被用于去寻找其他类型的结构。而聚类算法应该算是无监督学习算法中最容易理解和最广泛被应用的一种,所以,我们将以聚类算法作为我们讨论的第一个无监督学习算法。

那么,聚类算法一般都是用来干什么的呢?在我们最早的时候,曾经举过一些例子。比如,我们也说过在组织计算机集群的时候可能也有用,它的灵感是,如果我们知道数据中心里面,哪些计算机经常协作工作,那么我们可以重新分配资源,比如重新布局网络,由此优化数据中心,优化其中的数据通信。

再比如社交网络分析,事实上很多专家学者都在研究这样一些内容,他们关注一群人,关注社交网络,比如国外的Facebook,我们的微博,以在这些媒体上产生的关联为数据基础,比如你关注了谁,谁关注了你,你转发了谁的微博,谁转发了你的微博等等,由此找到关系密切的人,以及可能分析整个网络可以划分出来的各个小群体等等。

最后一个例子是,学者们也在使用聚类算法来了解星系的形成,然后使用它来了解天文学上的一些问题。

所以,这就是聚类。它将是我们介绍的第一个无监督学习算法。

K-means Algorithm[K-Means算法]

在聚类问题中,我们的数据都是没有标注信息的数据,而我们希望有一些算法可以自动地把这些数据分成有紧密关系的子集或者类簇。

K-means算法是现在最为广泛使用的聚类算法。所以,我们现在就来看看k-means算法以及它是怎样工作的。

k-means算法最好用图来说明。比如现在我们有一些这样没有标注的数据,而且我们想要把这些数据分成两个类簇。那么现在我们执行k-means算法,它的流程是这样的:

首先,我们随机初始化两个点,这两个点我们称他们为类簇中心点。所以,这个红色叉符号和蓝色叉符号代表的两个点就是我们初始的两个类簇中心点。因为我们希望最终能聚出两个类簇,所以我们这里需要两个初始化点。

k-means是一个迭代式的算法,而迭代的内容实际上只有两个步骤。第一个步骤就是,类簇分配;第二个则是重新计算类簇中心。那么这两个步骤具体是怎么做的呢,我们现在来看看。

在k-means算法的每次迭代中,第一步就是要进行类簇分配,它的意思是,我们要遍历所有的数据样本,就是我们这个图上的所有绿色的点,然后依据每一个点是更接近红色这个中心,还是蓝色的这个中心,来将每一个数据点分配到两个不同的聚类中心所代表的类簇上。

比如我们在这里示例的,我们遍历样本集中的每一个数据点,然后计算分别和红色叉、蓝色叉的距离,然后按照最近的那个进行着色。这样我们就可以得到我们这里的这个图。这就是类簇分配的步骤。

那么k-means聚类的另一部分,是要重新计算类簇中心点。具体的操作方法是:我们根据已经着色的这两个类,分别计算这两个类当前实际的均值点,然后以新计算得到的这两个均值点作为新的类簇中心点。所以,按照我们这个图里的情况,我们将计算所有红色点的均值,得到新的红色类簇的中心点。同样的,我们也计算所有蓝色点的均值,得到新的蓝色类簇的中心点。

  

然后,我们就又来到新的一轮迭代,那么就是再一次地进行类簇分配。所以,我们又重新遍历所有的样本,然后根据它们里红色中心近还是蓝色中心近来将它们划归到不同的类簇中,这里我们通过染色的方式来表达类簇分配。那么这么做了以后,我们再次重新计算中心点,我们就会完成一次新的迭代。

然后,我们再来做一轮迭代。也就是首先对它们再做一次类簇分配。然后再次重新计算每个类簇的均值点,将它们作为各自类簇新的中心点。

这个时候,我们基本上就完成了聚类了。实际上,如果在这个状态下,如果我们继续迭代,那么类簇的中心点就不会再发生改变,并且每个点的颜色也都不会再变了。所以,在这种时候,k-means算法就已经收敛了。我们可以看到,算法非常好地完成了在这个数据中找到了两个类簇的工作。

现在让我们来用更加形式化地方式来描述k-means算法。

k-means算法接受两个输入。第一个是参数k,表示我们想从数据中聚类出的类簇的个数,我们后面会讨论怎么选择k,不过现在暂时我们假设我们已经确定了我们所需要的类簇的个数,然后直接作为参数传递给算法就行了。

第二个参数就是无标注的训练数据集了,因为这是无监督学习,所以我们不需要标注y了,当然实际上我们本来也没有。

同时,在无监督算法中,我们约定x(i)是一个n维向量,我们也不需要x0,所以训练样本是n维向量,而不是n+1维了。这其实是因为,我们这里不需要对每个特征都需要学习出相对应的参数,所以也就不需要偏置项了,或者说截距项了。因此,我们就不再需要x0这个永远设置成1的项了。

我们这里形式化地描述下k-means算法的具体步骤。

第一步是,随机初始化k个类簇中心[μ1, μ2,… μk]。所以,对应前几张ppt中的图,我们的μ1可能就对应着红叉,μ2对应着蓝叉。不过,通常情况下我们可能不止两个类簇,所以我们使用k来表示类簇的个数。

那么我们这里需要一个循环来表达持续的迭代过程。我们将会重复做下面的这些事情:

首先,对于每一个样本,我们使用c(i)来表示样本点i属于哪个类簇,而我们对c(i)的赋值方式就是找到和i这个样本点最近的类簇中心,并将该中心所代表的类簇编号赋值给c(i)。我们这个过程其实也可以形式化地表达。所以,这就是第一步,进行类簇分配。

那么第二步,也就是重新计算各个类簇的中心点。所以,具体举个计算新类簇均值的例子。比如说,某个类簇中心μ2,被分配了一些训练样本x1,x5,x6,x10,这在我们这段代码中实际上是通过c1=2, x5=2, c6=2, c10=2来表示的。然后,我们就来计算这个类簇的均值,实际上也就是计算这四个点的均值。不过这里注意,我们的所有的样本都是n维向量,因此我们的μ2算完以后也是一个n维向量。所以,这样我们类簇2的中心点将变成这个刚刚计算得到的均值。

这里面有一个有意思的问题是,我们一直在说把样本分配给类簇中心点,但如果一个类簇中心点一个样本都没有分配到,这时候又该怎么办呢?这种时候,我们通常的操作就是简单地将这个类簇中心删除掉。那么,如果我们这么做了,我们最后当然只会得到k-1个类簇,而不是最初设置的k个。不过,如果有时候我们确实需要正正好的k个类簇,如果遇到了一个类簇中心分配不到任何一个样本点,那么我们就随机再生成一个类簇中心,然后再重复迭代就行了。不过更一般的情况,大多数时候我们还是直接删除掉那个类簇中心。这种事情理论上是会发生的,不过在实际中却不怎么常见。

到目前为止,我们一直在讨论的k-means算法都是应用在我们类似于左图的这种数据集上。它们都是很容易划分出不同类簇的数据,我们用k-means非常容易且很好地发现这些类簇,这种就有点类似我们之前在监督学习中讲的线性可分的情况一样,它们几乎都是样例式的数据,而在我们真实的应用中,数据集往往都是不是这样结构非常清晰、一目了然的。比如我们右图这个数据集,它看上去就没有那么清楚的内部结构。不过在我们右图这个例子中,我们的横轴是身高,纵轴是体重,假如我们得到了关于人类足够具有代表性的这样的数据,那么我们想要做的是,为一家生产T恤的厂商提供大、中、小号的建议,也就是我们的大号、中号、小号大概都应该覆盖什么样身材的人。

那么,完成这项工作的一种方法是,我们可以使用k-means算法来对这些数据聚类。所以,如果是这样,那么虽然最初的时候我们也无法轻松地观察出数据的内在类簇结构,但k-means还是或多或少地帮助我们把数据聚成了我们想要的三类。那么根据这个结果,我们就可以设定我们的大中小号分别都应该对应什么样身材的人。

所以,以上这些就是关于k-means算法的内容了。到目前为止,大家应该基本理解了k-means的基本思路,甚至可以自己编写k-means算法。不过这还都只是k-means算法的表层的介绍而已,接下来,让我们再讨论下k-means算法的核心,以便我们更加深入地理解k-means。

Optimization Objective[优化目标]

大部分监督学习算法,比如我们之前学习的线性回归,逻辑回归,svm等等,它们都有一个优化目标函数,或者某个代价函数需要通过算法进行最小化。

事实上,作为无监督学习算法, k-means算法也有一个优化目标函数,或者说需要最小化的代价函数。那么接下来,我们来看看它要优化的目标函数是什么。

虽然说,根据我们前面讲的k-means的算法内容,似乎没有任何需要优化的目标函数,而且即使我们不考虑目标函数或者代价函数,k-means算法也能正常地工作。但是,我们这里仍然还是要讨论下这个内容。原因有二:

  1. 首先,k-means是一个迭代算法。了解它的优化目标或者代价函数,有助于我们可以调试我们的k-means算法;
  2. 其次,也是更重要的目的,也是后面我们要进一步讨论的,我们如何找到更好的类簇以避免局部最优解。不过这个内容我们稍后在讨论。

现在让我们来看看k-means的最优化目标。

有了上面这些定义,那么我们的优化目标其实就可以写出来了,就是这里的式子。看上去很吓人,但是它表达的意义很清晰,我们来仔细看看。

k-means聚类算法需要最小化的代价函数,是函数J,它的参数是所有的c(i),也就是从c(1)一直到c(m),还有就是μ1到μk。随着算法的执行,这些参数将不断变化,而这个函数本身则是式子右侧的这个表达式,那么,k-means要做的是,就是找到参数ci和μi,并且尽量使得这个代价最小。

这里我们再解释一点细节。这里是我们的k-means的算法流程。

这里的第一步是为每一个训练样本点分配一个类簇。类簇分配步骤,它实际上做的就是对代价函数j进行最小化,但在这一步,我们是在调整ci这类参数,但保持了μi保持不变。所以,这一步做的就是不改变类簇的中心,但是会为每一个训练样本挑选类簇,使得整体的代价最小。这个可以很容易地进行数学证明,简单而言,因为挑选离自己最近的聚类中心作为自己的类簇,这会使得代价函数中的距离平方最小,所以在固定类簇中心μ不变的情况下,这将使得整个代价函数最小。

第二步,就是重新计算新的类簇中心。这一步做的,[最下方蓝色]实际上是在调整参数μi,使得整个代价函数最小化,但保持ci不变。这个也可以很容易地进行数学证明。简单而言,我们将类簇中心μi设置成该类簇所有样本的均值,这会使得该类簇下的所有距离差之和最小化。

所以,k-means实际上做的事情是,它使用两组参数,并把它们独立分成两部分。那么它首先调整c使得j最小化,然后再调整μ使得j最小化,然后不断如此迭代。

所以,这就是k-means所做的事情。那么我们现在就应该对k-means有很深入的理解了。那么也就具备了调试算法,并确保算法能够正确运行的能力了。

Random Initialization[随机初始化]

这里,我们来讨论下如何初始化k-means算法。而更加重要的是,这将引导我们讨论如何避开局部最优解来构建k-means聚类算法。

这就是我们前面讨论过了的k-means聚类算法。不过前面我们没有仔细讨论的事情是,这里的第一步,也就是随机初始化k个类簇中心点。我们随便想想,其实就能想出各种随机初始化的方法,不过事实上,有一种方法比其他大多数可能想到的方法更加高效。它可能是效果最好的一种方法。

这里展示了我们通常是如何初始化我们的类簇中心的。当运行k-means算法时,我们需要有一个类簇个数参数K,而它必然应当小于训练样本数m。

那么接下来,我们不是随机的初始出k个类簇中心,而是随机在现有的训练样本中挑选K个样本。然后,我们直接将这K个样本就设置成K个类簇的中心。

我们来看看一个具体的例子。假设我们设置K=2,那么我们的例子就在右侧这个图里,假设我们想要找到两个类簇。那么为了初始化两个类簇中心,我们要做的是,随机挑选几个样本,比如说我们挑选了这个样本和这个样本,然后分别将它们两作为两个类簇的中心,我们这里分别使用红色叉和蓝色叉表示。这样,一个随机初始化就完成了。

不过,我们画的这个随机选择似乎太过理想。但是,因为我们是随机挑选,所以有时候我们可能不会那么幸运,所以可能我们会选到这[下图]两个点。

所以,这就是我们应该如何随机初始化我们的类簇中心。所以,稍微形式化地说,我们初始化时,就是[左下蓝色板书]

大家是否还能想起我们演示k-means算法的时候是怎么随机初始化类簇中心的么?那时候我们用的初始化方法跟我们这里讲的不一样,那时候真的是随机初始化的k个点而已。而我们这里介绍的这种初始化类簇中心的方法才是真正被推荐的方法。所以,如果我们真的自己手动实现一个k-means算法的话,这才是需要被实现的方法。

不过,通过我们这里的两个随机选择类簇中心的例子,我们可能猜到,k-means最终可能会得到不同的结果。实际也是如此,由于初始化时,随机选择的类簇中心不同,k-means最后是可能得到不同的聚类结果的。

尤其是,如果k-means算法落在了局部最优解的时候,多次运行得到不同的聚类结果是很有可能发生的。

比如[左侧三个类],这里我们感觉它是很清楚的三个类簇。不过,如果我们运行k-means算法,我们可能会得到这样的很好的结果[右上]。

不过如果我们的运气很不好,那么初始化选择时我们就可能得到很差的结果,算法陷入到了局部最优解。比如我们右下角的这两个情况。

那么如果我们担心k-means算法会遇到局部最优解的问题,那么如果我们想要找到最可能的类簇结构的话,就像我们最上面这个图上做的一样。那么,我们能做的其实也很直观,那就是多尝试几次随机初始化,而不是仅仅只运行一次k-means就认为这是最佳的聚类结果。所以,我们需要运行多次k-means算法,通过多次随机初始化来得到一个足够好的结果。

具体地说,这些就是我们所能做的。比如我们可以运行一百次k-means算法,这是一个比较典型的运行次数设置,一般而言50~1000次都算比较常见。

这就意味着,我们每次都要随机初始化k个类簇中心,然后每次都迭代地去求解ci和μi,然后我们就可以计算损失函数J。

最终,我们完成这100次运行以后,我们会得到这100次运行对应的损失。那么很显然地,我们选择它们中代价最小的那个聚类结果。

一般来说,如果我们的k不是很大的话,比如在2~10之间,那么运行100次可能就可以找到很好的结果。不过如果k很大的话,比如超过10,甚至成百上千,那么多次尝试随机初始化可能就没什么帮助了。

Choosing the Number of Clusters[选择类簇数目]

接下来,我们来讨论下k-means算法中的最有一个细节,那就是怎么选择合适的类簇个数K。

虽然我们这里说想要选择最合适的K,但实际上并没有一个非常好的方法来完成这项任务,或者能够自动地做这件事。

到目前为止,用来决定类簇数目最常用的方法仍然是通过看可视化的图或者通过算法输出来人工地选择类簇个数K。不过确实会有很多人会问这样的问题,特别是在实际工作中,我们到底应该怎么设置类簇个数K。问这种问题其实是很自然的一个事情,但是我们得清楚,现在确实没有一个好的办法来自动地确定类簇的个数K,最常用的方法就是手动、人工地去指定类簇的数目。

之所以自动设定类簇数量k是一件不容易的事情的原因之一就是,通常在数据集中有多少个类簇是根本无法知晓的。比如我们看这里的这个数据集,[四个类]有些人可能认为这里面有四个类簇,那就设定k=4.

而另一些人可能觉得它们实际上就是两个大的类簇而已,这样的话,就设定k=2.

所以,即使是人来观察类似于这样的数据集,它的实际的内部类簇结构到底是怎样的,到底应该划分成几类,都是模棱两可、无法确定的。而且也无法说不同的答案之间谁一定是错误的,而谁又一定是正确的。而这就是无监督学习,我们不知道样本的类别标签,因此总是无法得到一个清晰的答案。

当人们在讨论如何选择K这个参数的时候,有一个可能会被提及的方法,叫做”肘部法则”。它其实并不是一个百试不爽的办法,不过有时它确实也能发挥作用。

那么,肘部法则是怎么做的呢。它实际上就是在不停地尝试不同的k值,比如从k=1开始,一直到某个比较大的值,比如我们这里是8,也就是最多猜测数据中只有8个类簇。那么我们就尝试每一个k的取值,并计算相对应的代价函数,这样我们就可以在这个图中把它们画出来。随着k的增加,我们的代价函数显然会越来越小,这样我们就可以得到一个随着K的取值而变化的代价函数的变化曲线。有可能我们就会得到这样的一条曲线,如果我们观察这条曲线,那么我们可以看到这里似乎有一个显著的转折点,看上去就像人的手臂肘部为止一样。这个点之前,代价函数下降得很快,但之后则很慢。所以,比如这个例子,看上去似乎k=3,也就是3个类簇是一个不错的选择。

如果我们应用肘部法则,并且我们得到的图形类似于这个图形,那么我们很幸运,按照这肘部点来设置k可能确实是很不错的选择。

不过,实际上肘部法则并不是那么常用。其中一个原因就在于,我们可能最终得到的一个曲线可能类似[右图]这样的比较平滑的曲线,这样的话,就看不出比较显然的肘部位置在哪里了。所以,就这个曲线而言,3似乎不错,但是4也不坏,5说不定也很合适。所以这样的话,我们其实就没办法清晰、确定地设置k了。

所以,肘部法则可能是一个值得尝试的办法,但是我们不应该对它抱有多高的期望。

最后,有另外一种方法来引导我们进行k的选择。

通常情况下,我们使用k-means算法是为了得到一些类簇用于后面的工作。比如我们可能会使用k-means来做市场分割,比如我们之前讨论的T恤尺码的例子。如果下游的这些工作可以有一些评估指标的话,那么一般而言,更好地确定k的方法是,看看不同的k,那个对下游的应用衡量指标有最好的表现。

我们继续来具体地看看T恤尺码地问题。这时候,我们可能会想着设计三种规格的T恤,小号、中号和大号。但也有可能想着设计五种规格的,超小号、小号、中号、大号、特大号。

那么,我们使用k=3和k=5分别去运行k-means算法。那么对于,k=3,我们可能会得到[左侧圈]这样的聚类结果。而对于,k=5,我们则可能会得到[右侧圈]这样的聚类结果。

这个例子的一个很好的地方在于,它可以给我们另一种选择k的思路。我们从T恤商业的角度上考虑,然后思考”如果我有五种规格的话,那么我们的T恤将会怎样满足用户,我可能会卖出多少件,我们的顾客是否会因为更加合身而更加满意之类的。”,也就是,我们是应该设计更多的规格来更好的满足顾客,还是说应该设计更少的规格以节约成本。所以,这种时候,考虑的往往是最终目标的一些衡量标准,而不是仅仅从数据上来确定k的取值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值