首页 文章 精选 留言 我的

精选列表

搜索[Python虚拟环境],共10000篇文章
优秀的个人博客,低调大师

python Kmeans算法解析

一. 概述 首先需要先介绍一下无监督学习,所谓无监督学习,就是训练样本中的标记信息是位置的,目标是通过对无标记训练样本的学习来揭示数据的内在性质以及规律。通俗得说,就是根据数据的一些内在性质,找出其内在的规律。而这一类算法,应用最为广泛的就是“聚类”。 聚类算法可以对数据进行数据归约,即在尽可能保证数据完整的前提下,减少数据的量级,以便后续处理。也可以对聚类数据结果直接应用或分析。 而Kmeans 算法可以说是聚类算法里面较为基础的一种算法。 二. 从样例开始 我们现在在二维平面上有这样一些点 x y 1.658985 4.285136 -3.453687 3.424321 4.838138 -1.151539 -5.379713 -3.362104 0.972564 2.924086 -3.567919 1.531611 0.450614 -3.302219 -3.487105 -1.724432 2.668759 1.594842 -3.156485 3.191137 3.165506 -3.999838 -2.786837 -3.099354 4.208187 2.984927 -2.123337 2.943366 0.704199 -0.479481 -0.392370 -3.963704 2.831667 1.574018 -0.790153 3.343144 2.943496 -3.357075 ... 它在二维平面上的分布大概是这样的: 好,这些点看起来隐约分成4个“簇”,那么我们可以假定它就是要分成4个“簇”。(虽然我们可以“看”出来是要分成4个“簇”,但实际上也可以分成其他个,比如说5个。)这里分成“4个簇“是我们看出来的。而在实际应用中其实应该由机器算得,下面也会有介绍的。 找出4个”簇”之后,就要找出每个“簇”的中心了,我们可以“看出”大概的中心点,但机器不知道啊。那么机器是如何知道的呢?答案是通过向量距离,也叫向量相似性。这个相似性计算有多种方法,比如欧式距离,曼哈顿距离,切比雪夫距离等等。 我们这里使用的是欧式距离,欧式距离其实就是反应空间中两点的直线距离。 知道这些后,我们就可以开始让机器计算出4个“簇”了。 主要做法是这样,先随机生成4个点,假设这4个点就是4个“簇”的中心。计算平面中每个点到4个中心点的距离,平面中每个点选取距离最近的那个中心作为自己的中心。 此时我们就完成第一步,将平面中所有点分成4个”簇“。但是刚刚那几个中心都是随机的,这样分成的4个簇明显不是我们想要的结果。怎么办呢?做法如下: 现在有4个簇,根据每个簇中所有点计算出每个簇的新中心点。这个新中心点就会比上一个旧的中心点更优,因为它更加中心。然后使用新中心点重复第一步的步骤。即再对平面中所有点算距离,然后分发到4个新簇中。不断迭代,直到误差较小。 这就是 Kmeans 算法的过程了。 三. 知识点浅析 3.1 确定“簇”的个数 上面所说的分成 4 个簇,这个 4 其实就是 Kmeans 中的K。要使用 Kmeans 首先就是要选取一个 K 作为聚类个数。而上面的例子其实是我们主观”看“出来的,但多数情况下我们是无法直观”看“出分多少个 K 比较好。那怎么办呢? 我们可以从较低的 K 值开始。使用较简单的 Kmeans 算法的结果(即较少的迭代次数,不求最佳结果,但求最快)。计算每个点到其归属的“簇”的中心点的距离,然后求和,求和结果就是误差值。然后再增加 K 值,再计算误差值。比如上面的例子,我们可以从 K=2 开始,计算 K 值从 2 到 7 的 Kmeans 算法的误差值。这样会得到类似这样一张图: 里面的 Error 可以理解未 Kmeans 的误差,而当分成越多“簇”的适合,误差肯定是越来越小。 但是不是“簇”越多越好呢?答案是否定的,有时候“簇”过多的话是不利于我们得到想要的结果或是做下一步操作的。 所以我们通常会选择误差减小速度比较平缓的那个临界点,比如上图中的 4。 可以发现,在分成 4 个簇之后,再增加簇的数量,误差也不会有很大的减少。而取 4 个簇也和我们所看到的相符。 3.2 欧式距离 3.2 欧式距离 欧氏距离是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,计算公式如下: 而本例种的是在二维空间种,故而本例的计算公式如下: 四. 代码和结果 加载数据的代码,使用了 numpy ,先是将代码加载成 matrix 类型。 import numpy as np def loadDataSet(fileName): ''' 加载数据集 :param fileName: :return: ''' # 初始化一个空列表 dataSet = [] # 读取文件 fr = open(fileName) # 循环遍历文件所有行 for line in fr.readlines(): # 切割每一行的数据 curLine = line.strip().split('\t') # 将数据转换为浮点类型,便于后面的计算 # fltLine = [float(x) for x in curLine] # 将数据追加到dataMat fltLine = list(map(float,curLine)) # 映射所有的元素为 float(浮点数)类型 dataSet.append(fltLine) # 返回dataMat return np.matrix(dataSet) 接下来需要生成 K 个初始的质点,即中心点。这里采用随机生成的方法生成 k 个“簇”。 def randCent(dataMat, k): ''' 为给定数据集构建一个包含K个随机质心的集合, 随机质心必须要在整个数据集的边界之内,这可以通过找到数据集每一维的最小和最大值来完成 然后生成0到1.0之间的随机数并通过取值范围和最小值,以便确保随机点在数据的边界之内 :param dataMat: :param k: :return: ''' # 获取样本数与特征值 m, n = np.shape(dataMat) # 初始化质心,创建(k,n)个以零填充的矩阵 centroids = np.mat(np.zeros((k, n))) # 循环遍历特征值 for j in range(n): # 计算每一列的最小值 minJ = min(dataMat[:, j]) # 计算每一列的范围值 rangeJ = float(max(dataMat[:, j]) - minJ) # 计算每一列的质心,并将值赋给centroids centroids[:, j] = np.mat(minJ + rangeJ * np.random.rand(k, 1)) # 返回质心 return centroids 欧式距离计算 def distEclud(vecA, vecB): ''' 欧氏距离计算函数 :param vecA: :param vecB: :return: ''' return np.sqrt(sum(np.power(vecA - vecB, 2))) cost 方法将执行一个简化的 kMeans ,即较少次数的迭代,计算出其中的误差(即当前点到簇质心的距离,后面会使用该误差来评价聚类的效果) def cost(dataMat, k, distMeas=distEclud, createCent=randCent,iterNum=300): ''' 计算误差的多少,通过这个方法来确定 k 为多少比较合适,这个其实就是一个简化版的 kMeans :param dataMat: 数据集 :param k: 簇的数目 :param distMeans: 计算距离 :param createCent: 创建初始质心 :param iterNum:默认迭代次数 :return: ''' # 获取样本数和特征数 m, n = np.shape(dataMat) # 初始化一个矩阵来存储每个点的簇分配结果 # clusterAssment包含两个列:一列记录簇索引值,第二列存储误差(误差是指当前点到簇质心的距离,后面会使用该误差来评价聚类的效果) clusterAssment = np.mat(np.zeros((m, 2))) # 创建质心,随机K个质心 centroids = createCent(dataMat, k) clusterChanged = True while iterNum > 0: clusterChanged = False # 遍历所有数据找到距离每个点最近的质心, # 可以通过对每个点遍历所有质心并计算点到每个质心的距离来完成 for i in range(m): minDist = np.inf minIndex = -1 for j in range(k): # 计算数据点到质心的距离 # 计算距离是使用distMeas参数给出的距离公式,默认距离函数是distEclud distJI = distMeas(centroids[j, :], dataMat[i, :]) # print(distJI) # 如果距离比minDist(最小距离)还小,更新minDist(最小距离)和最小质心的index(索引) if distJI < minDist: minDist = distJI minIndex = j # 更新簇分配结果为最小质心的index(索引),minDist(最小距离)的平方 clusterAssment[i, :] = minIndex, minDist ** 2 iterNum -= 1; # print(centroids) # 遍历所有质心并更新它们的取值 for cent in range(k): # 通过数据过滤来获得给定簇的所有点 ptsInClust = dataMat[np.nonzero(clusterAssment[:, 0].A == cent)[0]] # 计算所有点的均值,axis=0表示沿矩阵的列方向进行均值计算 centroids[cent, :] = np.mean(ptsInClust, axis=0) # 返回给定迭代次数后误差的值 return np.mat(clusterAssment[:,1].sum(0))[0,0] 最后可以调用 Kmeans 算法来进行计算。 def kMeans(dataMat, k, distMeas=distEclud, createCent=randCent): ''' 创建K个质心,然后将每个店分配到最近的质心,再重新计算质心。 这个过程重复数次,直到数据点的簇分配结果不再改变为止 :param dataMat: 数据集 :param k: 簇的数目 :param distMeans: 计算距离 :param createCent: 创建初始质心 :return: ''' # 获取样本数和特征数 m, n = np.shape(dataMat) # 初始化一个矩阵来存储每个点的簇分配结果 # clusterAssment包含两个列:一列记录簇索引值,第二列存储误差(误差是指当前点到簇质心的距离,后面会使用该误差来评价聚类的效果) clusterAssment = np.mat(np.zeros((m, 2))) # 创建质心,随机K个质心 centroids = createCent(dataMat, k) # 初始化标志变量,用于判断迭代是否继续,如果True,则继续迭代 clusterChanged = True while clusterChanged: clusterChanged = False # 遍历所有数据找到距离每个点最近的质心, # 可以通过对每个点遍历所有质心并计算点到每个质心的距离来完成 for i in range(m): minDist = np.inf minIndex = -1 for j in range(k): # 计算数据点到质心的距离 # 计算距离是使用distMeas参数给出的距离公式,默认距离函数是distEclud distJI = distMeas(centroids[j, :], dataMat[i, :]) # 如果距离比minDist(最小距离)还小,更新minDist(最小距离)和最小质心的index(索引) if distJI < minDist: minDist = distJI minIndex = j # 如果任一点的簇分配结果发生改变,则更新clusterChanged标志 if clusterAssment[i, 0] != minIndex: clusterChanged = True # 更新簇分配结果为最小质心的index(索引),minDist(最小距离)的平方 clusterAssment[i, :] = minIndex, minDist ** 2 # print(centroids) # 遍历所有质心并更新它们的取值 for cent in range(k): # 通过数据过滤来获得给定簇的所有点 ptsInClust = dataMat[np.nonzero(clusterAssment[:, 0].A == cent)[0]] # 计算所有点的均值,axis=0表示沿矩阵的列方向进行均值计算 centroids[cent, :] = np.mean(ptsInClust, axis=0) # 返回所有的类质心与点分配结果 return centroids, clusterAssment 选取不同的 k 值对结果影响有多大呢?我们来看看就知道了,下面给出的是 k 值为 2 到 6 的效果。图中红色方块即为“簇”的中心点,每个“簇”所属的点用不同的颜色表示。K = 2 K = 3 K = 4 K = 5 K = 6

优秀的个人博客,低调大师

python 运算符

算术运算符 下面列出一个表格,将所有的运算符表现出来。 运算符 描述 实例 + 加 - 两个对象相加 10+20 输出结果 30 - 减 - 得到负数或是一个数减去另一个数 10-20 输出结果 -10 * 乘 - 两个数相乘或是返回一个被重复若干次的字符串 10 * 20 输出结果 200 / 除 - x除以y 20/10 输出结果 2 % 取余 - 返回除法的余数 20%10 输出结果 0 ** 幂 - 返回x的y次幂 10**2 输出结果 100 // 取整除 - 返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0 比较运算符 且看下表: 以下假设变量 a为10,变量 b为20: 运算符 描述 实例 == 等于 - 比较对象是否相等 (a == b) 返回 False。 != 不等于 - 比较两个对象是否不相等 (a != b) 返回 true. > 大于 - 返回x是否大于y (a > b) 返回 False。 < 小于 - 返回x是否小于y (a < b) 返回 true。 >= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。 <= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 true。 上面的表格实例中,显示比较的结果就是返回一个true或者false,这是什么意思呢。就是在告诉你,这个比较如果成立,就是为真,返回True,否则返回False,说明比较不成立。 例子: >>> a=10 >>> b=20 >>> a>b False >>> a<b True >>> a==b False >>> a!=b True >>> a>=b False >>> a<=b True >>> c="5" #a、c是两个不同类型的量,能比较,但是不提倡这么做。 >>> a>c False >>> a<c True 逻辑运算符 布尔类型的变量 所谓布尔类型,就是返回结果为1(True)、0(False)的数据变量 布尔运算 看下面的表格,对这种逻辑运算符比较容易理解: (假设变量a为10,变量b为20) 运算符 描述 实例 and 布尔"与" - 如果x为False,x and y返回False,否则它返回y的计算值。 (a and b) 返回 true。 or 布尔"或" - 如果x是True,它返回True,否则它返回y的计算值。 (a or b) 返回 true。 not 布尔"非" - 如果x为True,返回False。如果x为False,它返回True。 not(a and b) 返回 false。 and and,翻译为“与”运算,但事实上,这种翻译容易引起望文生义的理解。先说一下正确的理解。A and B,含义是:首先运算A,如果A的值是true,就计算B,并将B的结果返回做为最终结果,如果B是False,那么A and B的最终结果就是False,如果B的结果是True,那么A and B的结果就是True;如果A的值是False ,就不计算B了,直接返回A and B的结果为False. 比如: 4>3 and 4<9,首先看4>3的值,这个值是True,再看4<9的值,是True,那么最终这个表达式的结果为True. >>> 4>3 and 4<9 True 4>3 and 4<2,先看4>3,返回True,再看4<2,返回的是False,那么最终结果是False. >>> 4>3 and 4<2 False 4<3 and 4<9,先看4<3,返回为False,就不看后面的了,直接返回这个结果做为最终结果。 >>> 4<3 and 4<2 False 前面说容易引起望文生义的理解,就是有相当不少的人认为无论什么时候都看and两边的值,都是true返回true,有一个是false就返回false。根据这种理解得到的结果,与前述理解得到的结果一样,但是,运算量不一样哦。 or or,翻译为“或”运算。在A or B中,它是这么运算的: if A==True: return True else: if B==True: return True else if B==False: return False 上面这段算是伪代码啦。所谓伪代码,就是不是真正的代码,无法运行。但是,伪代码也有用途,就是能够以类似代码的方式表达一种计算过程。 看官是不是能够看懂上面的伪代码呢?下面再增加上每行的注释。这个伪代码跟自然的英语差不多呀。 if A==True: #如果A的值是True return True #返回True,表达式最终结果是True else: #否则,也就是A的值不是True if B==True: #看B的值,然后就返回B的值做为最终结果。 return True else if B==False: return False 举例,根据上面的运算过程,分析一下下面的例子,是不是与运算结果一致? >>> 4<3 or 4<9 True >>> 4<3 or 4>9 False >>> 4>3 or 4>9 True not not,翻译成“非”,窃以为非常好,不论面对什么,就是要否定它。 >>> not(4>3) False >>> not(4<3) True 关于运算符问题,其实不止上面这些,还有呢,比如成员运算符in,在后面的学习中会逐渐遇到。 那么布尔型的变量有什么特点呢?下面就探索一下: >>> a 'http://hiekay.github.io' >>> bool(a) #布尔型,用bool()表示,就类似int(),str(),是一个内置函数 True >>> b="" >>> bool(b) False >>> bool(4>3) True >>> bool(4<3) False >>> m=bool(b) >>> m False >>> type(m) <type 'bool'> >>> 从上面的实验可以看出,如果对象是空,返回False,如果不是,则返回True;如果对象是False,返回False。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册