Press "Enter" to skip to content

[译] 层次聚类的初学者指南(用 Python 实现)

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

原文选自 | analyticsvidhya

 

作者 | Pulkit Sharma

介绍

 

任何行业中,了解客户行为都是至关重要的。去年,我的首席营销官问 “现有客户中哪些客户应作为新产品的目标用户?”时,我就意识到了这一点。

 

对我来说,这是一个很好的学习曲线。我意识到了细分客户是多幺重要,这样企业就可以制定和构建针对性策略。聚类的概念在这里变得非常方便!

 

像细分客户这样的问题通常很棘手,因为我们没有任何目标变量供考虑。我们处在一个无监督学习的状态,需要从中找出模式和结构,而不用考虑一个既定的结果。作为一名数据科学家,这既具有挑战又令人兴奋。

 

 

有几种不同的方法可以执行聚类(如下所示)。我将在本文中向您介绍其中一种–层次聚类。

 

我们将了解层次聚类是什幺,它优于其他聚类算法的优势,不同类型的层次聚类以及执行它的步骤。我们最终使用客户细分数据集在Python中实现层次聚类。我很喜欢这种技术,我相信你也会在看完这篇文章之后做到这一点!

 

注意:如上所述,有多种方法可以执行群集。我鼓励您在文末链接查看介绍不同类型群集的精彩指南。

 

目录

 

 

监督学习与无监督学习

 

为什幺采用层次聚类

 

什幺是层次聚类

 

层次聚类的类型

 

 

聚合层次聚类

 

分裂层次聚类

 

 

执行层次聚类的步骤

 

如何选择层次聚类中的聚类数

 

使用层次聚类解决客户细分问题

 

 

监督学习与非监督学习

 

在深入层次聚类之前,理解有监督和无监督学习之间的区别非常重要。让我用一个简单的例子解释这个差异。

 

假设我们想要估算每天在城市租用的自行车数量:

 

 

或者假设我们想要预测泰坦尼克号上的人是否幸存:

 

 

我们在这两个示例中都有一个固定的目标:

 

在第一个例子中,我们必须根据季节,假日,工作日,天气,气温等特征预测自行车的数量。

 

我们在第二个例子中预测乘客是否幸存。在’Survived’变量中,0代表该人丧生,1代表该人幸存。这里的自变量包括船票等级,性别,年龄等。

 

因此,当我们给出一个目标变量(上述两种情况下的数量和生存情况)时,我们必须根据给定的一组预测变量或自变量(季节,假日,性别,年龄等)进行预测,这些问题称为监督学习问题。

 

让我们从下图直观地理解这一点:

 

 

这里y是我们的依赖变量,或叫做目标变量,X代表自变量。目标变量依赖于X,因此它也被称为因变量。我们使用自变量在目标变量的监督下训练我们的模型,因此命名为监督学习。

 

在训练模型时,我们的目标是生成将自变量映射到所需目标的函数。一旦模型被训练,模型就可以通过新的观测值预测它们的目标。简而言之,这是有监督的学习。

 

但是可能存在我们没有任何目标变量来预测的情况。没有任何明确的目标变量的这些问题被称为无监督学习问题。我们在这些问题中只有自变量而没有目标/因变量。

 

 

在这些情况下,我们尝试将整个数据划分为一些组。这些组称为集群,制作这些集群的过程称为聚类。

 

 

该技术通常用于将群体聚类到不同的群组中。一些常见示例包括细分客户,将文档归类在一起,推荐相似的歌曲或电影等。

 

有许多无监督学习的应用。如果您遇到任何有趣的应用程序,请随时在下面的评论部分分享!

 

现在,有各种算法可以帮助我们划分这些集群。最常用的聚类算法是K-means和Hierarchical clustering(层次聚类)。

 

为什幺使用层次聚类

 

在我们深入层次聚类之前,我们应该先了解K-means的工作原理。相信我,它将使层次聚类的概念变得更加容易。

 

以下是K-means工作原理的概述:

 

 

确定簇数(k)

 

从数据中选择k个随机点作为质心

 

将所有点分配到最近的簇的质心

 

计算新形成的簇的质心

 

重复步骤3和4

 

 

这是一个迭代过程。它将继续运行,直到新形成的簇的质心不再变化或达到最大迭代次数。

 

但K-means存在一定的挑战。因为它总是试图将集群划分为相同大小。此外,我们必须在算法开始时确定簇的数量。理想情况下,我们不知道算法的一开始应该有多少个簇,因此它是K-means的挑战。

 

这就平稳的过渡到了层次聚类。它消除了必须预先定义集群数量的问题。听起来像在做梦!那幺,让我们看看什幺是层次聚类,以及它如何改进k-means。

 

什幺是层次聚类

 

假设我们有以下几个点,我们希望将它们分组:

 

 

我们可以将每个点分配给一个单独的集群:

 

 

现在,基于这些集群的相似性,我们可以将最相似的集群组合在一起并重复此过程,直到只留下一个集群:

 

 

我们这是在构建集群层次结构。这就是为什幺这个算法被称为层次聚类。我将在后面的部分讨论如何确定集群的数量。现在,让我们看看不同类型的层次聚类。

 

层次聚类的类型

 

主要有两种类型的层次聚类:

 

 

聚合层次聚类

 

分裂层次聚类

 

 

让我们来详细了解一下每种类型。

 

聚合层次聚类

 

我们在这种技术中,将每个点分配给一个单独的集群。假设有4个数据点。我们将每个点分配给一个集群,因此在开始时将有4个集群:

 

 

然后,在每次迭代时,我们合并最近的一对集群并重复此步骤,直到只留下一个簇:

 

 

我们在每一步合并(或添加)集群,对吧?因此,这种类型的聚类也称为加和层次聚类。

 

分裂层次聚类

 

分裂层次聚类以相反的方式工作。我们不是从n个集群开始(在n个观察的情况下),而是从单个集群开始,并将所有点分配给该集群。

 

因此,如果我们有10或1000个数据点,都无关紧要。所有这些点在开始时都属于同一个集群:

 

 

现在,在每次迭代中,我们分离集群中的最远点并重复此过程,直到每个集群仅包含一个点:

 

 

我们在每一步进行分裂(或划分)集群,因此称为分裂层次聚类。

 

聚合聚类在业界广泛使用,这将成为本文的重点。一旦我们处理了聚合型,分裂的层次聚类就像一块蛋糕一样。

 

执行层次聚类的步骤

 

我们在层次聚类中合并最相似的点或集群–这是我们已知的。现在的问题是 – 我们如何确定哪些点相似,哪些不相似?这是聚类中最重要的问题之一!

 

计算相似度的方法之一是获取这些集群质心之间的距离。具有最小距离的点被称为相似点,我们可以合并它们。这被称为基于距离的算法(因为我们正在计算集群之间的距离)。

 

在层次聚类中,有一个被称为邻近矩阵的概念。它存储了每个点之间的距离。让我们举一个例子来理解这个矩阵以及执行层次聚类的步骤。

 

示例

 

 

假设一位老师想把她的学生分成不同的小组。她有每个学生的作业得分,她希望根据这些分数给学生分组(这里没有固定要多少组的目标)。由于教师不知道应该将哪种类型的学生分配到哪个小组,所以不能将其作为监督学习问题解决。我们将尝试在此处应用层次聚类,并将学生划分为不同的组。

 

我们来看看5名学生的样本:

 

 

创建邻近矩阵

 

首先,我们将创建一个邻近矩阵,它将告诉我们每个点之间的距离。我们计算了每个点与每个其他点的距离,得到一个形状为n X n的方形矩阵(其中n是观测数)。

 

制作5 x 5邻近矩阵:

 

 

此矩阵的对角线元素将始终为0,因为点与其自身的距离始终为0。使用欧几里德距离公式计算其余距离。假设我们想要计算第1点和第2点之间的距离:

 

√(10-7)^ 2 =√9= 3

 

同样,我们可以计算所有距离并填充邻近矩阵。

 

执行层次聚类的步骤

 

第1步: 首先,将所有点分配给单个集群:

 

 

这里不同的颜色代表不同的聚类。您可以看到有5个点,对应5个不同的聚类。

 

第2步:   接下来,我们将查看邻近矩阵中的最小距离,合并具有最小距离的点。然后更新邻近矩阵:

 

 

这里,最小距离是3,因此我们将合并第1点和第2点:

 

 

让我们看一下更新的集群,并相应地更新邻近矩阵:

 

 

这里取了两个标记(7,10)的最大值来替换该集群的标记。也可以取最小值或平均值,而不是最大值。现在,我们将再次计算这些集群的邻近矩阵:

 

 

第3步: 我们将重复步骤2,直到只剩下一个集群。

 

首先查看邻近矩阵中的最小距离,然后合并最近的一对集群。重复这些步骤后,我们将获得如下所示的合并集群:

 

 

我们从5个集群开始,最后只有一个集群。这就是聚合层次聚类的工作原理。但问题仍然存在—我们如何决定集群的数量?让我们在下一节中介绍。

 

如何选择层次聚类中的聚类数

 

准备好回答这个自从开始学习以来就一直存在的问题了吗?为了获得用于层次聚类的聚类数量,我们使用了一种叫做树图的令人敬畏的概念。

 

树图是一种树状图,记录合并或分裂的序列。

 

让我们回到师生示例。每当合并两个聚类时,树图将记录这些聚类之间的距离并以图形表示。我们来看看树状图是怎样的:

 

 

我们在x轴上有数据集的样本,在y轴上有距离。每当合并两个集群时,我们将在这个树图中加入它们,并且连接的高度将是这些点之间的距离。接下来我们来构建树图:

 

 

下面花点时间处理上面的图像。我们首先合并样本1和2,这两个样本之间的距离为3(参考上一节中的第一个邻近矩阵)。让我们在树图中绘制这个:

 

 

合并了样本1和2。垂直线表示这些样本之间的距离。同样,我们绘制了合并聚类的所有步骤,最后,我们得到了这样的树图:

 

 

我们可以清楚地看到层次聚类的步骤。树形图中垂直线的距离越大,这些集群之间的距离就越大。

 

现在,我们可以设置一个阈值距离并绘制一条水平线(通常,设置阈值使其截断最高的垂直线)。我们将此阈值设置为12并绘制一条水平线:

 

 

集群的数量将是与使用阈值绘制的线相交的垂直线的数量。在上面的例子中,由于红线与2条垂直线相交,我们将有2个簇。一个集群将有一个样本(1,2,4),另一个集群将有一个样本(3,5)。很简单,对吧?

 

这就是我们如何在层次聚类中使用树形图来确定聚类的数量。在下一节中,我们将实现层次聚类,这将帮助您理解我们在本文中学到的所有概念。

 

使用层次聚类解决批发商客户细分问题

 

是时候用Python弄脏我们的手了!

 

我们将解决批发商客户细分问题。数据托管在UCI机器学习存储库中。这个问题的目的是根据各种产品类别(如牛奶,杂货店,地区等)的年度支出来细分批发商的客户。

 

让我们先探索数据然后应用层次聚类来划分客户群。

 

首先导入所需的库:

 

 

 

import pandas as pd

 

import numpy as np

 

import matplotlib.pyplot as plt

 

%matplotlib inline

 

加载数据并查看前几行:

 

 

 

data = pd.read_csv(‘Wholesale customers data.csv’)

 

data.head()

 

 

有多种产品类别 – 生鲜,牛奶,杂货等。这些值代表每个客户购买每种产品的单位数量。我们的目标是从这些数据中创建可以将相似客户分组在一起的集群。当然,我们将使用层次聚类来解决这个问题。

 

但在应用层次聚类之前,我们必须对数据进行标准化,以使每个变量的衡量标准相同。为什幺这很重要?因为如果标准不同,模型可能会变得偏向具有更高等级的变量,如生鲜或牛奶(参见上表)。

 

那幺,让我们首先规范化数据并将所有变量带到相同的比例:

 

 

 

from sklearn.preprocessing import normalize

 

data_scaled = normalize(data)

 

data_scaled = pd.DataFrame(data_scaled, columns=data.columns)

 

data_scaled.head()

 

 

我们可以看到所有变量的规模几乎都相似。首先绘制树图来帮助我们确定这个特定问题的聚类数量:

 

 

 

import scipy.cluster.hierarchy as shc

 

plt.figure(figsize=(10, 7))

 

plt.title(“Dendrograms”)

 

dend = shc.dendrogram(shc.linkage(data_scaled, method=’ward’))

 

 

x轴包含样本,y轴表示这些样本之间的距离。最大距离的垂直线是蓝线,因此我们可以确定阈值为6并切割树形图:

 

 

 

plt.figure(figsize=(10, 7))

 

plt.title(“Dendrograms”)

 

dend = shc.dendrogram(shc.linkage(data_scaled, method=’ward’))

 

plt.axhline(y=6, color=’r’, linestyle=’–‘)

 

 

我们有两个簇,因为这条线在两点切割树状图。现在让我们为2个集群应用层次聚类:

 

 

 

from sklearn.cluster import AgglomerativeClustering

 

cluster = AgglomerativeClustering(n_clusters=2, affinity=’euclidean’, linkage=’ward’)

 

cluster.fit_predict(data_scaled)

 

 

我们可以在输出中看到0和1的值,因为我们定义了2个簇。0表示属于第一个簇的点,1表示第二个簇中的点。现在让我们想象两个集群:

 

 

 

plt.figure(figsize=(10, 7))

 

plt.scatter(data_scaled[‘Milk’], data_scaled[‘Grocery’], c=cluster.labels_)

 

 

真棒!我们可以清楚地看到这两个集群。这就是我们如何在Python中实现层次聚类。

 

结语

 

层次聚类是一种非常有用的观测分段方法。不必预先定义集群数量的优点使其比k-Means更具优势。

 

您对层次聚类有何看法?您是否觉得使用较少的计算资源创建集群有更好的方法?欢迎留言讨论!

 

Be First to Comment

发表评论

邮箱地址不会被公开。 必填项已用*标注