Kmeans算法简单实现
平台:python
训练数据集:sklearn模块下的数据集
使用模块:
- import matplotlib.pyplot as plt:根据数据做出散点图
- from sklearn.datasets._samples_generator import make_blobs
- from scipy.spatial.distance import cdist:求样本点到质心的距离
- import numpy as np
生成数据集
x, y = make_blobs(n_samples=100, centers=6, random_state=1234, cluster_std=0.6)
重写fit和predict方法
class K_Means(object):
def __init__(self, n_clusters, max_iter, centroids=[]):
self.n_clusters = n_clusters
self.max_iter = max_iter
self.centroids = np.array(centroids, dtype=np.float)
def fit(self, data):
if (self.centroids.shape == (0,)):
self.centroids = data[np.random.randint(0, data.shape[0], self.n_clusters), :]
for i in range(self.max_iter):
c_ind = np.argmin(distance, axis=1)
for i in range(self.n_clusters):
if i in c_ind:
self.centroids[i] = np.mean(data[c_ind == i], axis=0)
def predict(self, samples):
distance = cdist(samples, self.centroids)
c_ind = np.argmin(distance, axis=1)
return c_ind
定义一个子绘图函数
def plotKMeans(x, y, centroids, subplot, title):
plt.subplot(subplot)# 传进来一个编号分配一个子图
plt.scatter(x[:, 0], x[:, 1], c='r')
plt.scatter(centroids[:, 0], centroids[:, 1], c=np.array(range(6)), s=100)
plt.title(title)
执行
if __name__ == '__main__':
kmeans = K_Means(n_clusters=6, max_iter=300, centroids=np.array([ [2, 1], [2, 2], [2, 3], [2, 4], [2,5],[2, 6]]))
plt.figure(figsize=(16, 6))
plotKMeans(x, y, kmeans.centroids, 121, 'Initial State')
kmeans.fit(x)
plotKMeans(x, y, kmeans.centroids, 122, 'Final State')
x_new = np.array([[0, 0], [10,7]])
y_pred = kmeans.predict(x_new)
print(kmeans.centroids)
print(y_pred)
plt.scatter(x_new[:, 0], x_new[:, 1], s=100, c='black')
plt.show()
输出如下:
完整代码解释如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 画图工具
import matplotlib.pyplot as plt
# 引入datasets里的make_blobs方法,直接生成聚类数据
from sklearn.datasets._samples_generator import make_blobs
"""
make_blobs函数
make_blobs函数是为聚类产生数据集,产生一个数据集和相应的标签
make_blobs(n_samples=100,n_features=2, centers=3, cluster_std=1.0, center_box=(-10.0,10.0), shuffle=True, random_state=None )
n_samples=100 ,表示数据样本点个数,默认值100;
n_features=2 ,是每个样本的特征(或属性)数,也表示数据的维度,默认值是2;
centers=3 ,表示类别数(标签的种类数),默认值3;
cluster_std=1.0 ,表示每个类别的方差,例如我们希望生成2类数据,其中一类比另一类具有更大的方差,可以将cluster_std设置为[1.0,3.0],浮点数或者浮点数序列,默认值1.0;
center_box=(-10.0,10.0) ,中心确定之后的数据边界,默认值(-10.0, 10.0);
shuffle=True ,将数据进行洗乱,默认值是True;
random_state=None ,官网解释是随机生成器的种子,可以固定生成的数据,给定数之后,每次生成的数据集就是固定的。若不给定值,则由于随机性将导致每次运行程序所获得的的结果可能有所不同。在使用数据生成器练习机器学习算法练习或python练习时建议给定数值。
make_blobs函数生成两个数组,
x是样本数组样本数组 [n_samples, n_features]产生的样本,
y是array of shape [n_samples]每个簇的标签,也就是六个类别,在本例中我们不需要y,只要用他的x来生成y
"""
# 生成100个样本点个数,根据6个中心点生成数据,随机生成种子,聚类的标准差,可以调
x, y = make_blobs(n_samples=100, centers=6, random_state=1234, cluster_std=0.6)
"""
figure绘图,语法说明:
figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)
num:图像编号或名称,数字为编号 ,字符串为名称
figsize:指定figure的宽和高,单位为英寸;
dpi参数指定绘图对象的分辨率,即每英寸多少个像素,缺省值为80 1英寸等于2.5cm,A4纸是 21*30cm的纸张
facecolor:背景颜色
edgecolor:边框颜色
frameon:是否显示边框
"""
# 指定figure的宽和高
plt.figure(figsize=(6, 6))
"""
scatter散点图参数说明:
x, y : 相同长度的数组,数组大小(n,),也就是绘制散点图的数据;
s:绘制点的大小,可以是实数或大小为(n,)的数组, 可选的参数 ;
c:绘制点颜色, 默认是蓝色'b' , 可选的参数 ;
marker:表示的是标记的样式,默认的是'o' , 可选的参数 ;
cmap:当c是一个浮点数数组的时候才使用, 可选的参数 ;
norm:将数据亮度转化到0-1之间,只有c是一个浮点数的数组的时候才使用, 可选的参数 ;
vmin , vmax:实数,当norm存在的时候忽略。用来进行亮度数据的归一化 , 可选的参数 ;
alpha:实数,0-1之间, 可选的参数 ;
linewidths:标记点的长度, 可选的参数 ;
"""
"""
x[m,n]:m代表第m维,n代表m维中取第几段特征数据
x[:,n]表示在全部数组(维)中取第n个数据,直观来说,x[:,n]就是取所有集合的第n个数据,
x[n,:]表示在n个数组(维)中取全部数据,直观来说,x[n,:]就是取第n集合的所有数据
"""
plt.scatter(x[:, 0], x[:, 1], c=y)
# 测试输出
# plt.show()
# 引入scrpy中的距离函数,默认欧氏距离,也可以在该库里使用其他的库
from scipy.spatial.distance import cdist
import numpy as np
# 定义一个类,继承object
class K_Means(object):
# 初始化,参数n_clusters(K)、迭代次数max_iter、初始质心 centroids
def __init__(self, n_clusters, max_iter, centroids=[]):
# 属性的定义,类似java里的构造器
self.n_clusters = n_clusters
self.max_iter = max_iter
# centroids传进的来是数组,需要转换为np里的array,数据类型之行为np的float
self.centroids = np.array(centroids, dtype=np.float)
# 训练模型方法,k-means聚类过程,传入原始数据,也就是make_blobs的x数据
def fit(self, data):
# 假如没有指定初始质心(也就是0行的矩阵),就随机选取data中的点作为初始质心
if (self.centroids.shape == (0,)):
# 没有的话,就赋一个值,从data里随机生成m个,data[m,:]选取随机行的值
# shape是描述数据长宽的列表,返回值是多少行多少列的两位数组,shape[0]是100,randint的第三个参数是随机生成几个,本例是6个
self.centroids = data[np.random.randint(0, data.shape[0], self.n_clusters), :]
# 开始迭代
for i in range(self.max_iter):
# 1. 计算距离矩阵,传入样本点和质心,所有的样本点和6个质心的距离同时算出来
# 得到的是一个100*6的矩阵,每一行代表每个样本点到所有质心的距离,每一行有6个值,每个值代表距离某个样本点的距离
distance = cdist(data, self.centroids)
# 2. 对距离按有近到远排序,选取最近的质心点的类别,作为当前点的分类
# 各排各的,排序之后我们不关心距离值是多少,只是想拿到对应下标,下标代表这个点具体属于哪个类
# 只取最小值,就不用排序了,axis=1的意思是每一行只取一列,最终得到一个100*1的矩阵
# axis的重点在于方向,而不是hang和列:
# 1表示横轴跨列,方向从左到右,沿着每一行或者列标签横向执行对应的方法;
# 0表示纵轴,方向从上到下,沿着每一列或行标签/索引值向下执行方法
# argmin取下标值
c_ind = np.argmin(distance, axis=1)
# 3. for循环对每一类数据进行均值计算,更新质心点坐标
for i in range(self.n_clusters):
# 排除掉没有出现在c_ind里的类别
# 如果这个质心在最小值距离的矩阵中。
# 反过来是:质心点有可能不在这个矩阵中,代表:
# 这个质心点距离每个样本点都不是最短的,那就没必要要这个质心点了
if i in c_ind:
# c_ind是数组,i是值,数组和值比较,则代表数组里每一个值都和这个i比较
# 布尔索引:拿出类别为true的所有值,为false的则不会被拿出
# 拿出一个一行两列的数据,
"""mean() 函数定义:
numpy.mean(a, axis, dtype, out,keepdims )
mean()函数功能:求取均值
经常操作的参数为axis,以m * n矩阵举例:
axis 不设置值,对 m*n 个数求均值,返回一个实数
axis = 0:压缩行,对各列求均值,返回 1* n 矩阵
axis = 1:压缩列,对各行求均值,返回 m *1 矩阵
"""
# centroids:质心坐标,所有点的均值坐标重新赋值给这个质心
# ???质心选的偏离过大,则不参与计算?
self.centroids[i] = np.mean(data[c_ind == i], axis=0)
# 实现预测方法
# samples:测试数据集
def predict(self, samples):
# 跟上面一样,先计算距离矩阵,然后选取距离最近的那个质心的类别
distance = cdist(samples, self.centroids)
c_ind = np.argmin(distance, axis=1)
# 返回:测试集里每个点距离最近质心(哪一类)的矩阵,[[分类1],[分类2],[分类3]]
return c_ind
# 定义一个绘制子图函数
# 传质心点,子图编号,子图标题标题
def plotKMeans(x, y, centroids, subplot, title):
# 分配子图,121表示1行2列的子图中的第一个
plt.subplot(subplot)# 传进来一个编号分配一个子图
# 构建一个散点图,第一列、第二列、指定一个颜色,c=y,也可以等于
plt.scatter(x[:, 0], x[:, 1], c='r')
# 画出质心点,质心点也是一组数,和x是一样类型的;6个质心点,分别给不同的颜色;s是大小
plt.scatter(centroids[:, 0], centroids[:, 1], c=np.array(range(6)), s=100)
# 给一个标题
plt.title(title)
if __name__ == '__main__':
kmeans = K_Means(n_clusters=6, max_iter=300, centroids=np.array([ [2, 1], [2, 2], [2, 3], [2, 4], [2,5],[2, 6]]))
plt.figure(figsize=(16, 6))
# 对初始位置进行画图
plotKMeans(x, y, kmeans.centroids, 121, 'Initial State')
# 对数据集进行聚类操作
kmeans.fit(x)
# 对聚类后的数据画图
plotKMeans(x, y, kmeans.centroids, 122, 'Final State')
# 对测试集数据进行分类预测
x_new = np.array([[0, 0], [10,7]])
y_pred = kmeans.predict(x_new)
# 输出聚类后的质心坐标
print(kmeans.centroids)
# 输出预测分类
print(y_pred)
# 将测试集数据在图中输出
plt.scatter(x_new[:, 0], x_new[:, 1], s=100, c='black')
plt.show()
([[0, 0], [10,7]])
y_pred = kmeans.predict(x_new)
# 输出聚类后的质心坐标
print(kmeans.centroids)
# 输出预测分类
print(y_pred)
# 将测试集数据在图中输出
plt.scatter(x_new[:, 0], x_new[:, 1], s=100, c='black')
plt.show()