赞
踩
K-Means算法是一种聚类分析(cluster analysis)的算法,其主要是来计算数据聚集的算法,主要通过不断地取离种子点最近均值的算法。
它的基本思想是,通过迭代寻找K个簇(Cluster)的一种划分方案,使得聚类结果对应的损失函数最小。其中,损失函数可以定义为各个样本距离所属簇中心点的误差平方和:
通过迭代不断的划分簇和更新聚类中心,直到每个点与其聚类中心的距离之和最小,停止迭代。要预先知道聚类簇的个数num,和初始化聚类中心centre。聚类簇的个数一般已知。而初始化聚类中心的值是随机初始化的。
选择K个点作为初始质心
repeat
将每个点指派到最近的质心,形成K个簇
重新计算每个簇的质心
until 簇不发生变化或达到最大迭代次数
其中,距离的计算可以选取欧式距离或曼哈顿距离等等。
1.自定义数据集:
sklearn.datasets.make_classification官网详解:http://sklearn.datasets.make_classification
- # 202011000106
-
- import matplotlib.pyplot as plt
- import numpy as np
-
- from sklearn import datasets
-
- # 产生多类单标签数据集,为每个类分配一个或多个正态分布的点集,为测试聚类算法而使用的
-
- # 数据集:
- x, y = datasets.make_classification(n_samples=200, # 默认样本个数是100个
- n_features=2, # 产生的默认特征 n_features 是两种,0 和 1
- n_informative=2, # 信息特征的数量
- n_redundant=0, # 冗余特征的数量
- n_repeated=0,
- n_classes=3, n_clusters_per_class=1, # 有三个类,每个类有一簇
- # 剩余都是默认值
- weights=None, flip_y=0.01, class_sep=1.0, hypercube=True, shift=0.0, scale=1.0,
- shuffle=True, random_state=0)
- # 返回值:xarray of shape [n_samples, n_features]是生成的样本;yarray of shape [n_samples]是每个样本的类成员的整数标签。
- plt.scatter(x[:, 0], x[:, 1], c=y)
- # 绘制散点图
- plt.show()
生成的散点图如下:
2.方法实现
- def kmeans(datas, num, threshold, maximum):
- # datas:输入数据;
- # num:聚类个数;
- # threshold:阈值;
- # maximum:最大迭代次数
-
- # result:最后聚类的结果
- result = np.zeros(len(datas))
- # 初始化result,np.zeros返回来一个给定形状和类型的用0填充的数组,即一个由200个0组成的一维数组
- # centre:聚类中心
- centre = np.random.random((num, len(datas[0])))
- # 返回一个num行2列的浮点数,浮点数都是从0-1之间随机取值,维度是2
- for i in np.arange(0, maximum):
- # 聚类:
- result = classify(datas, centre)
- # 对于每一次聚类求中心点:
- centre1 = centralization(datas, result, centre)
- # 欧氏距离:
- dis = distance(centre, centre1)
- if dis < 0:
- break
- centre = centre1
- print(centre.shape)
- return result
更新聚类归属:
- def classify(datas, centre):
- d = np.zeros((len(datas), len(centre)))
- # 输出结果:
- # len(datas)=200; len(centre))=num(聚类个数),即d是一个200*num的数组
- for i in np.arange(0, len(datas)):
- # 一共200个点,每一个点就都要经过聚类
- for j in np.arange(0, len(centre)):
- # @矩阵乘法:
- d[i][j] = (datas[i] - centre[j]) @ (datas[i] - centre[j])
- # 样本和各个质心的距离
- result = np.argmin(d, axis=1)
- # 返回向量中的最小值的索引,可以按行返回或者按列返回,axis=1按行取最小值,即取得距离哪一个类的距离最近
- return result
求和阈值比较的那个数字:
- def distance(datas, centre):
- d = np.zeros((len(datas), len(centre)))
- # 和上面一样
- for i in np.arange(0, len(datas)):
- for j in np.arange(0, len(centre)):
- d[i][j] = (datas[i] - centre[j]) @ (datas[i] - centre[j])
- return np.sqrt(np.sum(d))
- # np.sqrt返回一个非负平方根;np.sum对d里面的元素求和
更新聚类中心,返回一个新的聚类中心:
- def centralization(datas, result, centre):
- centre = np.zeros(centre.shape)
- # centre.shape输出结果为(3,2),即生成一个3*2的数组
- for i, n in zip(result, np.arange(0, len(result))):
- # 用序列解包同时遍历多个序列
- # https://www.cnblogs.com/Apy-0816/p/11100248.html
- centre[i] = centre[i] + datas[n]
- for i in np.arange(0, len(centre)):
- a = np.sum(result == i)
- centre[i] = centre[i] / a
- # 更新聚类中心
- return centre
- result = kmeans(x, 3, 2, 50)
- # 输入数据
- print(result)
- # 打印
- plt.scatter(x[:, 0], x[:, 1], c=result)
- plt.show()
- # 输出
一开始运行的时候,发现如下报错:
经过查找,发现是使用np.zeros()错误,是因为zeros()的第一个参数是决定数组的规格的,而第二参数是决定数据类型的,改正后的正确代码如下:
d = np.zeros((len(datas), len(centre)))
即添加双重括号即可解决。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。