Python Monte Carlo K-Means聚类实战研究

简介: Python Monte Carlo K-Means聚类实战研究

在本文中,188个国家基于这19个社会经济指标聚集在一起,使用Python实现的蒙特卡罗K-Means聚类算法。通过将类似国家分组在一起并对其进行概括,聚类可以帮助减少识别有吸引力的投资机会所需的工作量。

在讨论聚类国家和得出结论的结果之前,本文详细介绍了距离度量,聚类质量测量,聚类算法,K-Means聚类算法。




聚类理论 - 相似与距离的度量

聚类是将一组异构(不同)对象划分为同类(相似)对象的子集的过程。聚类分析的核心是假设给定任何两个对象,您可以量化这些对象之间的相似性或不相似性。在连续搜索空间中距离测量相似性。

下面我写了关于连续搜索空间的相似性度量。对于每个我都包含公式(给定两个向量,  和q)和Python代码。用于编写本文的所有Python代码都可用。

class Similarity:
 

    def __init__(self, minimum):
        self.e = minimum
        self.vector_operators = VectorOperations()

    def manhattan_distance(self, p_vec, q_vec):
        """
        This method implements the manhattan distance metric
        :param p_vec: vector one
        :param q_vec: vector two
        :return: the manhattan distance between vector one and two
        """
        return max(np.sum(np.fabs(p_vec - q_vec)), self.e)

    def square_euclidean_distance(self, p_vec, q_vec):
        """
        This method implements the squared euclidean distance metric
        :param p_vec: vector one
        :param q_vec: vector two
        :return: the squared euclidean distance between vector one and two
        """
        diff = p_vec - q_vec
        return max(np.sum(diff ** 2), self.e)

聚类理论 - 聚类算法类

聚类算法的两个主要类别是分层聚类和分区聚类。分层聚类通过将小聚类合并为较大的聚类或将较大的聚类分成较小的聚类来形成聚类。分区聚类通过将输入数据集划分为互斥的子集来形成聚类。

分层和分区聚类之间的差异主要与所需的输入有关。分层聚类仅需要相似性度量,而分区聚类可能需要许多额外的输入,最常见的是簇的数量。一般而言,分层聚类算法也更适合于分类数据。ķķ


分层聚类

有两种类型的层次聚类,即凝聚聚类和分裂聚类。凝聚聚类是一种自下而上的方法,涉及将较小的聚类(每个输入模式本身)合并为更大的聚类。分裂聚类是一种自上而下的方法,从一个大型集群(所有输入模式)开始,并将它们分成越来越小的集群,直到每个输入模式本身都在集群中。


分区聚类

在本文中,我们将重点介绍分区聚类算法。分区聚类算法的两个主要类别是  基于质心的聚类  和  基于密度的聚类。本文重点介绍基于质心的聚类; 特别是流行的K-means聚类算法。





聚类理论 - K-Means聚类算法

K-Means聚类算法是一种基于质心的分区聚类算法,它使用均值漂移启发式算法。K均值聚类算法包括三个步骤(初始化,分配和更新)。重复这些步骤,直到聚类已经收敛或已经超过迭代次数,即计算预算已用尽。


初始化

在搜索空间中随机初始化一组质心。这些质心必须与聚类的数据模式处于同一数量级。换句话说,如果数据模式中的值介于0到100之间,则初始化值介于0和1之间的随机向量是没有意义的。

 

注意:确保跨每个属性规范化数据,而不是每个模式


分配

一旦质心在空间中被随机初始化,我们迭代数据集中的每个模式并将其分配给最近的质心。尝试并行执行此步骤,尤其是在数据集中有大量模式的情况下。

更新

一旦将模式分配给它们的质心,就应用均值漂移启发式。此启发式替换每个质心中的每个值,并将该值的平均值替换为已分配给该质心的模式。这将质心移向属于它的图案的高维平均值。均值漂移启发式问题在于它对异常值敏感。为了克服这个问题,可以使用K-medoids聚类算法  ,也可以使用  标准化数据来抑制异常值的影响,

 

迭代

重复这三个步骤进行多次迭代,直到聚类已经收敛于解决方案。一个非常好的GIF显示如下所示,


PYTHON代码 - 聚类类的补充

下面的Python方法是Clustering类的扩展,它允许它执行K-means聚类算法。这涉及使用均值漂移启发式更新质心。

 


聚类理论 - 聚类质量的度量

假设您有一定的相似度和数据聚类,您仍然需要一个目标函数来衡量该聚类的质量。大多数群集质量指标都尝试根据群集间和群集内距离来优化群集。简单地说,这些指标试图确保同一集群中的模式紧密相连,不同集群中的模式相距甚远。


量化误差

量化误差测量由量化引入的舍入误差,即将一组输入值映射到有限的较小集合。这基本上是我们通过将模式聚类到k个集群中所做的事情。

注意:图像还假设我们使用曼哈顿距离。

在量化误差的上述说明中,我们计算每个模式与其分配的质心之间的平方绝对距离之和。


戴维斯 - 布尔丁指数

戴维斯-尔丁标准是基于一个特定的聚类的簇内和簇间的距离比。

注意:图像假设我们使用曼哈顿距离。

在Davies-Bouldin指数的上图中,我们有三个由三个模式组成的集群。


剪影指数

该  剪影指数是衡量一个特定的聚类质量的最流行的方式之一。它衡量每个模式与其自身集群中的模式的相似程度,与其他集群中的模式进行比较。

 def silhouette_index(self, index):
     
        # store the total distance to each cluster
        silhouette_totals = []
        # store the number of patterns in each cluster
        silhouette_counts = []
        # initialize the variables
        for i in range(self.solution.num_clusters):
            silhouette_totals.append(0.0)
            silhouette_counts.append(0.0)
        s = Similarity(self.e)
        for i in range(len(self.solution.patterns)):
            # for every pattern other than the one we are calculating now
            if i != index:
                # get the distance between pattern[index] and that pattern
                distance = s.fractional_distance(self.solution.patterns[i], self.solution.patterns[index])
                # add that distance to the silhouette totals for the correct cluster
                silhouette_totals[self.solution.solution[i]] += distance
                # update the number of patterns in that cluster
                silhouette_counts[self.solution.solution[i]] += 1
        # setup variable to find the cluster (not equal to the pattern[index]'s cluster) with the smallest distance
        smallest_silhouette = silhouette_totals[0] / max(1.0, silhouette_counts[0])
        for i in range(len(silhouette_totals)):
            # calculate the average distance of each pattern in that cluster from pattern[index]
            silhouette = silhouette_totals[i] / max(1.0, silhouette_counts[i])
            # if the average distance is lower and it isn't pattern[index] cluster update the value
            if silhouette < smallest_silhouette and i != self.solution.solution[index]:
                smallest_silhouette = silhouette
        # calculate the internal cluster distances for pattern[index]
        index_cluster = self.solution.solution[index]
        index_silhouette = self.e + silhouette_totals[index_cluster] / max(1.0, silhouette_counts[index_cluster])
        # return the ratio between the smallest distance from pattern[index] to another cluster's patterns and
        # the patterns belong to the same cluster as pattern[index]
        return (smallest_silhouette - index_silhouette) / max(smallest_silhouette, index_silhouette)

高轮廓值表示žž  与其自己的簇很好地匹配,并且与相邻簇很不匹配。人们应该致力于为数据集中的每个模式最大化小号一世小号一世。

注意:图像还假设我们使用曼哈顿距离。


在使用这些指标过去几个月后,我得出的结论是,它们都不是完美的,

  1. 量化误差 - 该度量的计算复杂度最小,但是度量偏向大量群集,因为当您添加更多质心时,群集会变得更小(更紧凑),并且在极端情况下,您可能会为每个群集分配一个模式质心。在这种情况下,量化误差被最小化。使用这个指标The Good,结果是最可信  
  2. 戴维斯 - 布尔丁 - 随着你增加的值,ķķ每个质心之间的距离平均会自然减少。因为这个术语在分母中,所以对于较大的值,最终除以较小的数字ķķ。其结果是度量偏向于具有较少数量的簇解决方案。
  3. Silhouette Index - 这个指标的计算复杂性是疯狂的。假设您计算从每个模式ž一世ž一世到每个其他模式的距离,以计算哪个簇最接近,并且您为每个模式执行此操作,则需要计算| Z | * | Z -1 ||ž|*|ž- 1|距离。在这个例子中,相当于35,156次计算。如果你完美地记忆,每次传球的计算次数减半。

以下对不同指标的分析很好地证明了这些偏差; 尽管事实上他们应该测量相同的东西,但他们几乎完全是负相关的。


X QE D B SI
QE 1.0 -0.965 -0.894
SB -0.965 1.0 0.949
SI -0.894 0.949 1.0





PYTHON代码 - 聚类

在评估给定聚类的适应性之前,您需要实际聚类模式。Clustering类包含将模式分配给最近的质心的方法。

 

PYTHON代码 - 目标函数

ClusteringQuality类测量给定输入模式的聚类的质量。

 

聚类理论 - 聚类中的蒙特卡罗方法

K-Means聚类算法的两个最大问题是:

  1. 它对质心的随机初始化很敏感
  2. 初始化的质心数,ķķ

由于这些原因,K-means聚类算法经常重启多次。因为初始化(通常)是随机的,所以我们基本上对质心的随机高维起始位置进行采样,这也称为蒙特卡罗模拟。为了比较独立模拟的解决方案,我们需要衡量集群质量,例如前面讨论过的那些。


确定性初始化

我说初始化通常是随机的,因为K-Means聚类算法有确定性初始化技术。


随机初始化

不同之处在于伪随机序列中的下一个随机数与先前的随机数无关,而在准随机数序列中,下一个随机数取决于先前的随机数。相关随机数覆盖搜索空间的更大表面。

比较二维空间中的伪随机序列(左)和准随机序列(右)


选择正确的K

除了测试不同的初始化之外,我们还可以在蒙特卡罗框架中测试不同的值ķķ。目前,没有动态确定正确数量的聚类的最佳方式,尽管总是正在研究用于确定正确ķķ值的技术。我更愿意只是凭经验尝试不同的k值并比较结果,尽管这很费时,特别是在大型数据集上。


聚类结果 - 可视化和质心分析

下面提出的最终结果表示发现在范围最好聚类ķ = { 6 ,7 ,8 }ķ={6,7,8}超过1000独立每的每一个值的模拟ķķ。欧几里德距离和量化误差是蒙特卡罗K均值聚类中使用的距离和质量度量。用于产生结果的数据集是2014年的标准化时间点数据集,其中包括19个被确定为与实际GDP增长正相关的社会经济指标。


群集细分和质心分析

下面的每个标签都将集群分解为属于它的国家,并将质心与我们聚集的19个社会经济指标中的每一个的中心质心进行比较。


 

2014年该群组中的国家/地区

 







聚类结果 - 结论和进一步研究

量化不是风险管理,衍生品定价或算法交易; 它是关于挑战事情的方式,并通常使用统计和计算方法找到更好的方法。

2004年,美国是一个异常值,并且自己占据了一个集群。该集群的特点是PPP的汇率低,进口高,出口高,家庭支出高,工业生产高,政府收入相对较高,特别是在健康方面。在这个时间点,最大的差异仍然是中国发生的投资数量要大得多,而且人口(人口在15到64岁之间)人口更多(显然)更大。在工业生产方面,中国也超过了美国。这些在下面的并排比较中显示,




诸如东欧与西欧国家之类的俗语出现在地图上,并且(因为缺乏一个更好的词)正确。然而,诸如金砖四国(巴西,俄罗斯,印度,中国和南非)之类的口语显然更多地受到政治经济的驱动,而不是实际经济。以下是我对一些常见口语的看法,

  1. 东欧与西欧 - 第一组中的国家与第五组和第二组中的国家之间似乎有明显的区别。过去十年来,西班牙,爱尔兰,捷克共和国和其他附近国家发生了变化。这可能是主权债务危机的结果。
  2. 东西方国家 - 这是一种过度简化。大多数亚洲国家占据不同的集群,而美国和英国等传统的西方国家实际上并不占据同一集群。
  3. 金砖四国 - 巴西,俄罗斯,印度,中国和南非属于不同的集群。虽然他们可能已达成贸易协议,但这并不意味着这些国家具有相同的社会,人口和经济构成或未来实际GDP增长的相同潜力。
  4. 非洲增长故事 - 虽然资本市场在过去十年中表现良好,但这似乎并没有反映出非洲大陆的社会,人口和经济构成的重大变化。有趣的是,印度和巴基斯坦不再与中非和南非国家聚集在一起。
  5. 北非与南部非洲 - 北非国家(摩洛哥,阿尔及利亚,埃及,利比亚等)与非洲其他国家之间存在明显区别。令人惊讶的是,南非现在与这些国家聚集在一起。
  6. 新兴国家与发达国家 - 这似乎过于简化了。似乎有一些发展阶段将在下一节讨论。

还有更多的俗语,我为不评论所有这些而道歉,这六个只是我日常生活中经常遇到的那些。如果您发现其他有趣的关系,请评论。由于我们不知道每个社会经济指标的相对重要性,因此无法量化在一个集群与另一个集群中的有多好。在某些情况下,我们甚至无法确定大或小的价值是好还是坏。例如,如果政府效率低下,政府的大笔支出是否仍然有效?尽管如此,我还是试图构建一个粗略的度量标准来对每个集群进行排名:

排名=出口+家庭支出+进口+改善卫生+改善水+人口+ 15岁至64岁人口增长+总投资+城市百分比+手机订阅+政府收入+政府支出+医疗支出+工业生产+互联网用户 - PPP的汇率 - 失业率 - 年龄依赖率

根据此指标,每个群集的相对排名如下所示,


排名值 计数

6

10.238 1 2

8

5.191 2 22

1

5.146 3 20

5

3.827 4 20

2

3.825 5 45

4

3.111 6 32

3

3.078 7 4

7

1.799 8 43





这个排名并不完美,但它再次证实了我们的观点,即世界是一个不平等的地方。

那对投资者意味着什么呢?我认为这意味着应该在处于不同发展阶段的国家之间作出区分。这是因为虽然大多数欠发达国家代表的是具有最大回报潜力的投资,但它们的风险也更大,可能需要更长的时间才能获得回报。理想情况下,这些因素应相互权衡,并与投资者的风险回报偏好进行比较。


相关文章
|
2天前
|
数据采集 机器学习/深度学习 人工智能
Python编程入门:从基础到实战
【10月更文挑战第24天】本文将带你进入Python的世界,从最基础的语法开始,逐步深入到实际的项目应用。我们将一起探索Python的强大功能和灵活性,无论你是编程新手还是有经验的开发者,都能在这篇文章中找到有价值的内容。让我们一起开启Python的奇妙之旅吧!
|
3天前
|
JavaScript 数据安全/隐私保护 Python
python爬取m3u8实战!!
本文详细介绍了如何抓取和处理m3u8视频文件,包括从网页源代码中提取m3u8文件地址、下载m3u8文件及其对应的ts片段、处理加密的ts文件以及使用ffmpeg合并视频片段。通过多线程下载和文件路径处理,确保了高效和准确的视频抓取与合并。文中还提供了具体的Python代码示例,帮助读者理解和实现整个过程。
14 1
|
16天前
|
机器学习/深度学习 数据挖掘 Serverless
手把手教你全面评估机器学习模型性能:从选择正确评价指标到使用Python与Scikit-learn进行实战演练的详细指南
【10月更文挑战第10天】评估机器学习模型性能是开发流程的关键,涉及准确性、可解释性、运行速度等多方面考量。不同任务(如分类、回归)采用不同评价指标,如准确率、F1分数、MSE等。示例代码展示了使用Scikit-learn库评估逻辑回归模型的过程,包括数据准备、模型训练、性能评估及交叉验证。
38 1
|
17天前
|
调度 开发者 Python
探索Python中的异步编程:从基础到实战
【10月更文挑战第9天】在Python的世界中,异步编程是一个让开发者既能提升应用性能又能保持代码可读性的强大工具。本文将带你一探究竟,从理解异步编程的基本概念开始,到深入剖析其背后的原理,再到通过实际代码示例掌握其应用技巧。无论你是异步编程的新手还是希望深化理解的老手,这篇文章都将为你打开一扇新的大门,让你的项目因使用异步而更加高效和强大。
|
22天前
|
存储 人工智能 Java
Python编程入门:从基础到实战
【10月更文挑战第4天】本文旨在为初学者提供一个全面而深入的Python编程学习路径。我们将从Python的基本语法和概念开始,然后逐步深入到更复杂的主题,如数据结构、面向对象编程和异常处理等。最后,我们将通过一些实际的项目案例,帮助读者将理论知识应用到实践中去。无论你是编程新手,还是有一定经验的开发者,都可以在这篇文章中找到适合自己的学习内容。让我们一起开启Python编程的学习之旅吧!
|
22天前
|
数据挖掘 程序员 调度
探索Python的并发编程:线程与进程的实战应用
【10月更文挑战第4天】 本文深入探讨了Python中实现并发编程的两种主要方式——线程和进程,通过对比分析它们的特点、适用场景以及在实际编程中的应用,为读者提供清晰的指导。同时,文章还介绍了一些高级并发模型如协程,并给出了性能优化的建议。
22 3
|
21天前
|
数据采集 程序员 开发者
Python编程入门:从基础到实战
【10月更文挑战第5天】本文旨在为初学者提供一条清晰的Python学习路径,涵盖基础知识、关键概念、实战项目以及常见问题解答。我们将通过简单易懂的语言和实际代码示例,帮助读者快速掌握Python编程技能。无论你是零基础的新手还是有一定经验的开发者,都能在这篇文章中找到有价值的信息。让我们一起开启Python编程之旅吧!
|
1天前
|
开发者 Python
探索Python中的异步编程:从基础到实战
【10月更文挑战第25天】在Python的世界中,异步编程如同一股清泉,为处理并发任务带来了新的思路。本文将带你领略异步编程的魅力,从其基本概念出发,通过实际代码示例,逐步深入到异步IO、异步网络请求等高级话题。你将看到,使用asyncio库如何简化并发编程,以及如何在实际应用中利用这些知识来提升程序的性能和响应性。
|
19天前
|
开发者 Python
Python中的元类深度剖析与实战应用
Python中的元类深度剖析与实战应用
20 0
|
23天前
|
数据采集 数据可视化 数据挖掘
Python 数据分析实战:使用 Pandas 进行数据清洗与可视化
【10月更文挑战第3天】Python 数据分析实战:使用 Pandas 进行数据清洗与可视化
64 0