Kmeans入门

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()

输出如下:

image-20210411021725538

完整代码解释如下:

#!/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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值