Kmeans聚类分析

  • 前言
  • 什么是聚类?
  • 聚类与分类的区别
  • Kmeans算法常用的距离公式
  • Kmeans算法流程
  • Kmeans实践
    • 读取数据并可视化
    • 簇分配和质心移动
      • 初始化K个质心
      • 把每个样本分配予最近的质心
      • 重新计算每一簇的质心,移动质心
      • 判定移动质心是否对结果提升
      • 直至收敛
    • 聚类过程可视化
      • 质心分割
      • 质心移动轨迹和簇分布
  • Kmeans算法优缺点分析
  • Kmeans算法应用场景
  • 参考文献

前言

我们之前遇到的所有机器学习算法都属于带标签的监督算法,而实现生活中大部分数据是不带标签的,从今天起我们要学一些处理不带标签数据的非监督算法,先从Kmeans聚类算法开始,我们将从以下几个方面来介绍Kmeans聚类算法

  • 什么是聚类?
  • 聚类与分类的区别
  • Kmeans算法常用的距离公式
  • Kmeans算法流程
  • Kmeans算法实践
  • Kmeans算法优缺点分析
  • Kmeans算法应用场景

什么是聚类?

俗话说:“物以类聚,人以群分”,意思是说具有共同特质的人或物更容易聚集在一起,聚类算法正是依循这一客观规律,通过技术手段,将相似的研究对象聚集在同一个类里面,将相异的研究对象聚集在不同类里面,使得同一个类里面的研究对象具有极大的相似性,不同类的研究对象具有极大的差异性,聚类后的研究对象的内在结构就更加清楚明了。

聚类与分类的区别

聚类和分类看起来都是把一些样本分到相同或者不同的类,但是两者却有着本质区别,尤其是初学者对聚类和分类还是很难分清楚的,可以从以下几个方面来进行区分

(1) 目的

聚类的目的是要找出数据之间的相似性和相异性,在聚类之前并不清楚到底分多少类,也不清楚每个类里面包含哪些样本,甚至用什么方式方法来分也不确定,侧重总结归纳,而分类是在“分”之前就清楚知道总共有多少类,现在要确定新的样本到底属于哪个类,侧重预测。

(2) 操作

聚类是不需要利用已知数据进行训练的,直接聚类出结果,而分类是需要利用已有的数据训练出一个可靠的模型,然后利用这个模型去预测新的样本并给出判定,是一个训练加预测的过程;

(2) 范畴

正如上面所提,聚类是不需要利用已有的训练模型来对未知数据做预测,不需要数据类别标签,属于无监督学习,而分类是需要有一个训练过程得到一个训练模型,这个训练是有数据类别标签参与的,属于有监督学习。

Kmeans算法常用的距离公式

数学上常用距离来度量两个对象之间相隔多远,除此之外,距离还可以用来表示研究对象之间的近似程度,而聚类算法就是要根据研究对象的相似程度来决定哪些应该聚在一起,哪些不应该聚在一起,在聚类算法里面常用的一些距离公式有欧几里得距离,曼哈顿距离,闵可夫斯基距离,切比雪夫距离,夹角余弦距离和杰卡德距离等。设x(i)x^{(i)}x(i) 和x(j)x^{(j)}x(j)是样本空间里的两个样本点,其分量分别如下

(x1(i),x2(i),...,xn(i))(x_1^{(i)}, x_2^{(i)},..., x_n^{(i)}) (x1(i)​,x2(i)​,...,xn(i)​)

(x1(j),x2(j),...,xn(j))(x_1^{(j)}, x_2^{(j)},..., x_n^{(j)}) (x1(j)​,x2(j)​,...,xn(j)​)

(1) 欧几里得距离

欧几里得距离,又叫欧式距离,是生活,研究中最常用的距离公式,用来表示欧式空间里面两个对象的远近程度,x(i)x^{(i)}x(i) 和x(j)x^{(j)}x(j)的欧式距离可以用如下表达式来计算

d(x(i),x(j))=∑s=1n(xs(i)−xs(j))2d(x^{(i)}, x^{(j)}) = \sqrt {\sum\limits_{s =1}^n (x_s^{(i)}- x_s^{(j)})^2}d(x(i),x(j))=s=1∑n​(xs(i)​−xs(j)​)2​

Kmeans算法默认的就是欧式距离。

(2) 曼哈顿距离

曼哈顿距离也叫出租车距离或者城市距离,常用来刻画网格上面两点之间距离,其表达式如下

d(x(i),x(j))=∑s=1n∣xs(i)−xs(j)∣d(x^{(i)}, x^{(j)}) = \sum\limits_{s =1}^n |x_s^{(i)}- x_s^{(j)}|d(x(i),x(j))=s=1∑n​∣xs(i)​−xs(j)​∣

(3) 闵可夫斯基距离

稍微复杂的距离公式还有闵可夫斯基距离公式,其表达式如下

d(x(i),x(j))=(∑s=1n(xs(i)−xs(j))q)1/qd(x^{(i)}, x^{(j)}) =(\sum\limits_{s =1}^n (x_s^{(i)}- x_s^{(j)})^q)^{1/q}d(x(i),x(j))=(s=1∑n​(xs(i)​−xs(j)​)q)1/q
可以看到曼哈顿距离是闵科夫斯基距离当q=1的特例,欧几里得距离是闵科夫斯基距离当q=2的特例。

(4) 切比雪夫距离

d(x(i),x(j))=max⁡1≤s≤n∣xs(i)−xs(j)∣d(x^{(i)}, x^{(j)}) = \max\limits_{1\leq s \leq n} |x_s^{(i)}- x_s^{(j)}|d(x(i),x(j))=1≤s≤nmax​∣xs(i)​−xs(j)​∣

由上式可以看到切比雪夫距离是闵科夫斯基距离的q趋向无穷大的极限形式,如果x(i)x^{(i)}x(i) 和x(j)x^{(j)}x(j)某些个分量差距很大,用切比雪夫距离有天然优势。

(5) 夹角余弦距离

如果把两个样本看成向量的话,可以计算向量之间的夹角,于是有了夹角余弦距离,一般的,如果夹角越小,相似度越高,反之,相似度越小,其表达式如下

cos(θ)=(x(i),x(j))∣x(i)∣∣x(j)∣=∑s=1nxs(i)xs(j)∑s=1n(xs(i))2∑s=1n(xs(j))2cos(\theta) = \frac{(x^{(i)}, x^{(j)})}{|x^{(i)}||x^{(j)}|}=\frac{\sum\limits_{s =1}^n x_s^{(i)} x_s^{(j)}}{\sqrt{\sum\limits_{s =1}^n (x_s^{(i)})^2}\sqrt{\sum\limits_{s =1}^n (x_s^{(j)})^2} }cos(θ)=∣x(i)∣∣x(j)∣(x(i),x(j))​=s=1∑n​(xs(i)​)2​s=1∑n​(xs(j)​)2​s=1∑n​xs(i)​xs(j)​​

夹角余弦距离常用来刻画文本相似度。

(6) 杰卡德距离

如果是两个集合,不关心集合里面具体元素,还可以用杰卡德距离,先介绍杰卡德相似系数,假设现有集合A和集合B, 其杰卡德相似系数公式如下

J(A,B)=∣A∩B∣∣A∪B∣J(A,B) = \frac{|A\cap B|}{|A\cup B|}J(A,B)=∣A∪B∣∣A∩B∣​

杰卡德相似系数表示两个集合的交的元素占两个集合的并的元素的比例,特别的,A与B完全相同,则∣A∩B∣=∣A∪B∣|A\cap B| = |A\cup B|∣A∩B∣=∣A∪B∣,则J(A,B)=1

而杰卡德距离是在杰卡德系数的基础上再进一步加工

dist(A,B)=1−J(A,B)=∣A∪B∣−∣A∩B∣∣A∪B∣dist(A,B) = 1 - J(A,B) = \frac{|A\cup B|-|A\cap B|}{|A\cup B|}dist(A,B)=1−J(A,B)=∣A∪B∣∣A∪B∣−∣A∩B∣​

dist(A,B)表示A与B之间的距离,距离越小,相似度越高,反之,相似度越低。

Kmeans算法流程

Kmeans算法包括簇分配和质心移动两个基本步骤,具体的

(1)初始化K个质心;

(2)计算每个样本到K个质心的距离,把每个样本分配予最近的质心,完成簇分配,记录此时每个样本的簇标签和整体损失函数;

(3)重新计算每一簇的质心,移动质心,同时,计算此时的整体损失函数;

(4)如果(3)的整体损失函数比(2)的整体损失函数小,重复第二步第三步,直到整体损失函数不再下降为止;

Kmeans算法流程如下

Created with Raphaël 2.2.0初始化K个质心簇分配&质心移动损失函数收敛?输出聚类结果yesno

Kmeans实践

我们以吴恩达机器学习第七次作业为例子来进行实践,详细具体的掌握Kmeans算法。

读取数据并可视化

原始数据能够可视化的尽量可视化,原始数据可视化最大的好处就是非常直观的看到数据分布,猜到最佳聚类的数目和最后的大致效果。

import math
import numpy as np
import pandas as pd
import scipy.io as scio
import matplotlib.pyplot as plt#数据可视化
data = scio.loadmat("D:\项目\机器学习\吴恩达机器学习课件\CourseraML\ex7\data\ex7data2.mat") #读取数据
X = data["X"]  #50*2维数组
plt.figure(figsize=(6,4)) #新建画布
plt.scatter(X[:,0], X[:,1]) #散点图
plt.xlabel("X1")
plt.ylabel("X2")
plt.show()

由于原来的数据是mat格式的,这里我们要用scipy模块io类的loadmat函数读取数据,查看数据基础信息,发现数据主体 X 其实是一个50*2维的数组,只有2个特征,那么可以用matplotlib模块可视化,从样本的散点图能够非常直观的看到最佳的聚类数目为 3。

簇分配和质心移动

利用散点图知道聚多少类之后,就有的非常关键参数K,接下来要做的就是严格按照Kmeans算法流程中的簇分配和质心移动。

初始化K个质心

实践表明第一步K个质心的选择好坏直接关系到最终的收敛效果和收敛步数,在初始质心的选择上面有两个关键因素需要考虑

一个是随机性

随机性是指初始质心的选择可以有很多种可能,可以是原样本点,也可以是非原样本点,一般选择原样本点比较好。

一个是离散性

虽然随机性可以让初始质心有很多种选择,但是质心又有牵引的作用,为保障最终收敛效果和收敛步数,初始质心还应该尽可能离散。

initial_centroids = X[np.random.permutation(len(X))[0:K],:] #随机取K个样本作为初始质心

这行代码是将原样本空间随机打乱再取打乱后样本空间的前面K个,相当于从原样本空间随机抽取了K个样本。

把每个样本分配予最近的质心

有了初始K个质心,就可以计算每一个样本到这些质心的距离,这样每个样本就会产生K个距离,可以比较这K个距离的大小,选出最小距离对应的那个质心,并将该样本划归到这个质心簇里,并标记该样本的所属的簇号,这样每个样本也有了一个簇标签,完成了第一轮簇分配。

def find_closet_centroids(myX, my_init_centroids): #给出初始聚类中心点,计算每个样本到中心点的距离并划分类m = myX.shape[0] #样本数K = my_init_centroids.shape[0] #聚类个数idx = np.zeros([m, 1]) #用来存放簇中心for i in range(m): #对每一个样本循环distance = [] #用来存放距离,每一个样本有k个距离for j in range(K):#print(myX[i,:], centeriods[j,:], myX[i,:] - centeriods[j, :])dist = np.linalg.norm(myX[i,:] - my_init_centroids[j,:]) #每个样本都有k个距离,二阶范数即欧氏距离distance.append(dist) idx[i] = np.argmin(distance) #k个距离中取最小的return idx

重新计算每一簇的质心,移动质心

每个样本都有了自己所属的簇标签后,就可以重新计算该簇的质心,一般以该簇的算术平均值作为新的质心,该簇的质心移动到新的质心上。

def compute_centroids(myX, myidx): #重新计算簇中心m = myX.shape[0] #样本数n = myX.shape[-1] #特征数K = 3 #簇数centroids = np.zeros((K, n)) #簇*特征数,如同前面的initial_centroidscounts = np.zeros((K, n)) #簇*特征数,用来存放各簇的样本数for i in range(m):centroids[int(myidx[i])] += myX[i] #簇求和counts[int(myidx[i])] +=1 #簇计数new_centroids = centroids/counts #簇平均值return new_centroids

判定移动质心是否对结果提升

在评价质心的移动对聚类结果是否有提升需要一个评价尺度,也就是要设计一个整体损失函数来刻画每一步的操作是否对结果是否有提升,如果有提升,那么就沿着这个方向继续进行下去,如果没有提升就要考虑停下来,或者转变方向。在设计整体损失函数时候,需要考虑样本情况,也需要质心情况,以及前后可对比性。Kmeans聚类算法的整体损失函数可以设计成

Cost(c1,...,cm,uc1,...,ucK)=1m∑i=1m(x(i)−uci)2Cost(c_1,...,c_m, u^{c_1},...,u^{c_K}) = \frac{1}{m}\sum\limits _{i=1}^m (x^{(i)} -u^{c_i})^2 Cost(c1​,...,cm​,uc1​,...,ucK​)=m1​i=1∑m​(x(i)−uci​)2

其中,cic_ici​ 代表样本 x(i)x^{(i)}x(i) 被分配的簇标签,ci∈{1,2,...,K}c_i\in \{1,2,...,K\}ci​∈{1,2,...,K},μciμ^{c_i}μci​代表x(i)x^{(i)}x(i)被分配簇标签所对应的质心。 整体损失函数是一个收敛函数,如果下一轮算出的值比上一轮的值小,说明质心的移动确对结果有所提升,反之,质心移动没有对结果提升,达到收敛状态。

def cost(myX, myidx, centroids): #计算损失函数cost_value = 0for i in range(len(myX)):cost_value += np.sum((X[i] - centroids[int(myidx[i])])**2)cost_value /= len(myX) #整体损失值return cost_value

直至收敛

有了前面几小步的准备工作,现在要做的就是将其封装起来,给出整体损失函数,并设置收敛条件让其一步一步的去进行簇分配和质心移动工作,直至收敛为止。

def run_kmeans(myX, K): #在样本上运行kmeans算法m = myX.shape[0] #样本数n = myX.shape[1] #特征数centroids = [] #用来存放每一步的簇中心cost_values = [] #用来存放每一步的整体损失值initial_centroids = myX[np.random.permutation(m)[0:K],:] #随机取K个样本作为初始中心点centroids.append(initial_centroids) #把初始中心点追加进去initial_idx = find_closet_centroids(myX, initial_centroids) #计算每个样本到中心点的距离,并返回类别标签initial_cost_value = cost(myX, initial_idx, initial_centroids) #计算第一次的整体损失函数cost_values.append(initial_cost_value) #把第一次整体损失函数追加进去new_centroids = compute_centroids(myX, initial_idx) #重新计算聚类中心centroids.append(new_centroids) #把新的聚类中心追加进去new_cost_value = cost(myX, initial_idx, new_centroids) #重新计算整体损失函数,此时只是质心改变,类别标签并没改变cost_values.append(new_cost_value) #把新损失函数值追加进去while cost_values[-2]>cost_values[-1]: #判定损失函数值是否降低idx = find_closet_centroids(myX, centroids[-1]) #以新的质心进行簇分配centroid = compute_centroids(myX, idx)cost_value = cost(myX, idx, centroid)centroids.append(centroid)cost_values.append(cost_value)   return idx, centroids, cost_values

聚类过程可视化

虽然前面实现了聚类模型,如果能够将聚类过程可视化呈现一定是锦上添花,更加能够明白聚类原理。

质心分割

由于之前的质心是以数组统一保存起来,但是在绘制质心移动轨迹的时候并不好用,所以需要做一个质心分割工作,简单的来说就是将所有质心分成K组,代表K个簇,每一组都有迭代次数个质心点坐标, 这样没一簇的质心移动就清晰了

def centroid_split(mycentroids, K): #将所有中心点分簇step = len(mycentroids) #收敛步数cluster_center = []#用来存放各簇的中心点坐标for k in range(K):for i in range(step):cluster_center.append(tuple(mycentroids[i][k]))cluster_center_k = [cluster_center[i:i+step] for i in range(0, len(cluster_center), step) ]  #每簇的簇中心点坐标return cluster_center_k

质心移动轨迹和簇分布

这一部分需要将最后收敛状态下每簇的样本分布区分开来,并且把各簇的质心移动轨迹绘制出来

def visual_Kmeans(myX, K): #可视化Kmeans过程plt.figure(figsize=(6,4)) #新建画布plt.subplot(1,2,1) #第一个子图plt.xlabel("X1")plt.ylabel("X2")idx, centroids, cost_values = run_kmeans(myX, K)plt.scatter(myX[:,0], myX[:,1], c = idx) #根据idx标签绘制各簇散点图cluster_center = centroid_split(centroids, K) #中心点分簇for k in range(K): #绘制K个簇中心移动轨迹centroid_x = [] #用来存放每簇的中心点的每一步的x1值centroid_y = [] #用来存放每簇的中心点的每一步的x2值cluster_xy = cluster_center[k]for s in range(len(cluster_xy)):centroid_x.append(cluster_xy[s][0])centroid_y.append(cluster_xy[s][1])plt.plot(centroid_x, centroid_y, '-->' , linewidth = 0.7)plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=0.2) #调整子图间距plt.subplot(1,2,2) #第二个子图plt.plot([i for i in range(len(cost_values))], cost_values) #损失函数折线图plt.xlabel("iteration")plt.ylabel("cost")plt.show()

Kmeans算法优缺点分析

  • 优点

(1) 适用性强

很多未知特性的数据集都可以先用K-means去试试,探索数据内在结构。

(2) 过程简单

  • 缺点

Kmeans聚类算法的缺点也很明显,如

(1) 需要事先知道聚类数目;

参数K作为一个输入参数,是在聚类之前就要根据业务或者经验来确定;

(2) 初始质心选择影响很大;

因为初始质心选择上要具备随机性,存在一些不确定因素,并不能保证每一次初始化聚类操作都能开始于一个合适的状态,不恰当的初始质心可能使得损失函数在聚类过程中陷入局部最小值,达不到全局最优的状态,下图是多次初始质心选择聚类结果和损失函数收敛情况。

从上图可以看到前3次聚类并没有达到全局最优化,这正是因为初始质心的选择不当导致的。

Kmeans算法应用场景

Kmeans聚类算法的应用场景很多,凡是一些不代标签的数据需要聚类的都可以用Kmeans算法试一试。这里重点介绍一下Kmeans在反欺诈领域的应用,在反欺诈领域经常利用过往欺诈性索赔的黑数据,根据数据的相似性来提炼欺诈方式和欺诈模式,还可以识别新的欺诈行为。

参考文献

1, permutation用法

https://blog.csdn.net/ljyljyok/article/details/102929918

2, 调整子图间距

https://blog.csdn.net/zengbowengood/article/details/103279583

3, 多张静态图变成动图imageio

https://blog.csdn.net/zengbowengood/article/details/109336369

机器学习——聚类分析相关推荐

  1. 机器学习--聚类分析(划分方法,层次方法、密度方法)

    本节学习聚类分析,聚类属于无监督学习,其中聚类的方法有很多种常见的有K-means.层次聚类(Hierarchical clustering).谱聚类(Spectral Clustering)等,在这 ...

  2. 如何自学python爬虫-Python初学者如何从网络爬虫到机器学习?

    很多同学选择了Python作为其学习编程的首选语言,而Python也以其容易上手的语法.广泛的应用领域.不断旺盛的市场需求回报着每一个学习者和应用者. 今天我们来说说Python的一个热门的应用领域- ...

  3. 【总目录】人工智能、机器学习、深度学习总结大全----目录.未完待续...

    文章目录 @[toc] 一.Python 二.爬虫 三.Mysql 四.MongoDB 五.Numpy 六.Scipy 七.Pandas 八.其他常用工具 九.可视化工具Matplotlib 十.数理 ...

  4. 【机器学习入门】深入浅出聚类算法!如何对王者英雄聚类分析,探索英雄之间的秘密...

    Datawhale 作者:小一,Datawhale优秀学习者 寄语:首先,对聚类算法进行了介绍:然后,解释了EM算法E步.M步的原理:最后,对sklearn参数进行了详解,并对王者荣耀英雄利用EM算法 ...

  5. python文本聚类分析_python机器学习kmeans算法——对文本进行聚类分析

    #!/usr/bin/env python#-*- coding: utf-8 -*-#@File : kmeans.py#@Author: 田智凯#@Date : 2020/3/19#@Desc : ...

  6. matlab中k-means算法_机器学习 | KMeans聚类分析详解

    大量数据中具有"相似"特征的数据点或样本划分为一个类别.聚类分析提供了样本集在非监督模式下的类别划分.聚类的基本思想是"物以类聚.人以群分",将大量数据集中相似 ...

  7. 机器学习笔记(3)——使用聚类分析算法对文本分类(分类数k未知)

    聚类分析是一种无监督机器学习(训练样本的标记信息是未知的)算法,它的目标是将相似的对象归到同一个簇中,将不相似的对象归到不同的簇中.如果要使用聚类分析算法对一堆文本分类,关键要解决这几个问题: 如何衡 ...

  8. 机器学习实践:足球比赛聚类分析--11

    机器学习实践:足球比赛聚类分析 1.实验描述 本实验利用K-Means聚类分析算法对足球比赛结果进行分析,该算法通过Sprak Mllib库来调用,我们将学习K-Means算法的K值选取,聚类原理等内 ...

  9. K-means聚类分析-机器学习

    大量数据中具有"相似"特征的数据点或样本划分为一个类别.聚类分析提供了样本集在非监督模式下的类别划分.聚类的基本思想是"物以类聚.人以群分",将大量数据集中相似 ...

最新文章

  1. SparkSQL Spark on Hive Hive on Spark
  2. 学习结构[记录]类型(9) - 变体结构
  3. 浏览器打开html文件显示中文乱码解决方法
  4. Codeforces Round #345 (Div. 2)
  5. 『设计模式』设计模式--模板方法模式
  6. Word中如何设置图片与段落的间距为半行
  7. Redis实现消息队列之生产消费模式
  8. 让百度地图API支持HTTPS
  9. 《推荐系统笔记(四)》svd的python计算实例
  10. 两个原生JS跨页面传值的小方法
  11. 计算机网络超详细笔记(五):网络层
  12. soundpool android,Android SoundPool:再次播放停止的声音
  13. python判断三位数水仙花数_Python如何判断一个数字是否为水仙花数
  14. 计算机组成原理笔记(王道考研) 第七章:输入输出系统
  15. JAVA之HttpClient+Jsoup实现代理IP爬虫
  16. 应用系统安全规范-自己想到和网络搜索到的点子记录整合一下
  17. 咖说 | 姚前:区块链与央行数字货币
  18. matlab 梯度图像,在matlab中快速计算图像的梯度
  19. JsonUtils的实现:对象与json相互转换
  20. 开发容器式微服务的第一步

热门文章

  1. java课程设计 华容道_Java课设-数字华容道
  2. 大学生python心得1000字_大学生心得体会1000字
  3. 从一个html页面传值到另一个页面,两个html之间的值传递(js location.search用法)
  4. vue项目通讯录_vue 自定义组件实现通讯录功能
  5. mysql 查看版本的几种方法
  6. BOOT ROM 初始化内容、启动设备、镜像烧写
  7. C++题解:CSP迎国庆热身公益赛T2——猜数游戏(70分)
  8. pta 天梯赛 7-3 换硬币 (20 分)day4
  9. 某音提取真机cookie,cookie参数解密
  10. ffmpeg推送rtsp流或者视频文件到rtsp服务器