【机器学习】 k-means聚类算法

k-means算法原理

输入:类簇个数K,迭代终止条件
for m ← 1 to M:
	//M是数据集中数据的个数
	for k ← 1 to K:
		//k是各类簇的中心点
		保留到m欧式距离最近的k,将m归入k簇
while 不达到终止阈值θ:
	计算各类簇的新中心点k,中心点k为k类簇各点的均值
	for m ← 1 to M:
		for k ← 1 to K:
			保留到m欧式距离最近的k,将m归入k簇
	计算是否达到终止条件
输出:聚类结果

关于终止条件:

  1. 一般终止条件为每个数据归属的簇不再变化,或k-means算法的损失函数变化小于某一阈值
  2. k-means算法的损失函数为:
    R S S k = m ω k m μ ( ω k ) 2 RSS_k=\displaystyle\sum_{m\in\omega_k}|m-\mu(\omega_k)|^2
    R S S = k = 1 K R S S k RSS=\displaystyle\sum_{k=1}^{K}RSS_k
    其中 ω k \omega_k 是每个簇中所有的点, μ ( ω k ) \mu(\omega_k) 是k这个簇的聚类中心

k-means算法的两个大问题是:

  1. 第一次聚类中心的选取
  2. 聚类中心个数k的选取

k-means算法python实现

# -*- coding:utf-8 -*-

import random
import numpy as np
import math
import matplotlib.pylab as plt


def create_the_dataset(size, min, max):
    # 随机生成数据集,size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值
    dataset = []
    sub_dataset = []
    for i in range(size):
        sub_dataset.append(random.uniform(min, max))
        sub_dataset.append(random.uniform(min, max))
        dataset.append(sub_dataset)
        sub_dataset = []

    dataset = np.mat(dataset)
    # 将列表变成矩阵
    # 数据集是(size,2)的矩阵

    return dataset


def get_euclidean_distance(point, center):
    # 计算两个点的欧式距离
    # 输入是两个(1,2)的矩阵
    # np.power((矩阵1-矩阵2),2)分别计算两个矩阵每一列相减后的二次方,结果是一个(1,2)的矩阵
    euclidean_distance = math.sqrt(np.sum(np.power((point - center), 2)))

    return euclidean_distance


def initialize_the_center(dataset, k):
    # 生成聚类中心,dataset是矩阵数据类型的数据集,k是要生成的聚类中心的数量
    center = np.mat(np.zeros((k, 2)))
    for i in range(2):
        Range = float(max(dataset[:, i]) - min(dataset[:, i]))
        # 矩阵某一列的范围,也就是(最大值-最小值)
        center[:, i] = min(dataset[:, i]) + Range * np.random.rand(k, 1)
        # 对应这列的k个值是这列的(最小值+范围×随机生成的一组符合01之间的均匀分布的系数)

    # 中心是(k,2)的矩阵
    return center


def visualization(center, clusterAssment, dataset):
    # 画点
    dataset = dataset.tolist()
    center = center.tolist()
    clusterAssment = clusterAssment.tolist()
    # 将数据变成列表类型

    color = ['red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna',
             'silver', 'skyblue', 'slateblue', 'slategray', 'snow', '#FFFAFA', 'springgreen', 'steelblue', 'tan',
             'teal', 'thistle']
    x = []
    y = []
    for i in range(len(center)):
        x.append(center[i][0])
        y.append(center[i][1])
        plt.scatter(x, y, color=color[i], s=40)
        x = []
        y = []
        for j, each in enumerate(clusterAssment):
            if each[0] == i:
                x.append(dataset[j][0])
                y.append(dataset[j][1])
        plt.scatter(x, y, color=color[i+1], s=40)
        x = []
        y = []
	
	plt.savefig("k-means.png")
    plt.show()


def kmeans(size, min, max, k):
    # k-means算法的实现
    # size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值,k是选取的聚类中心的个数
    dataset = create_the_dataset(size, min, max)
    # 生成数据集
    center = initialize_the_center(dataset, k)
    # 初始化聚类中心
    clusterAssment = np.mat(np.zeros((size, 2)))
    # (size,2)的矩阵,用于判断每个数据归属的聚类中心是否还发生变化
    # 每一行第一列是聚类中心的序号,第二列是到聚类中心的距离

    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        for i in range(size):
            minDist = np.inf
            # 对于每一个数据,先设置最小距离是无限大
            minIndex = -1
            # 设置离它最近的点序号是-1

            for j in range(k):
                distJI = get_euclidean_distance(dataset[i, :], center[j, :])
                # 计算一个数据和一个聚类中心的欧式距离

                if distJI < minDist:
                    # 保留最小的那个欧式距离和对应的聚类中心序号
                    minDist = distJI
                    minIndex = j
            if clusterAssment[i, 0] != minIndex:
                # 如果其中一个聚类中心变化了,就继续循环
                clusterChanged = True
            clusterAssment[i, :] = minIndex, minDist ** 2

        for cent in range(k):
            # 更新聚类中心
            dataCent = dataset[np.nonzero(clusterAssment[:, 0].A == cent)[0]]
            # clusterAssment[:, 0].A(size,1)的矩阵变成size行1列的tuple
            # clusterAssment[:, 0].A中每行和cent比较,相等返回True,不想等返回False
            # np.nonzero返回为True的索引(非零元素的索引)
            # 因为dataset和clusterAssment是一一对应的,所以通过clusterAssment索引到每类的每个数据
            center[cent, :] = np.mean(dataCent, axis=0)
            # axis=0是普通的将每一列相加,而axis=1表示的是将向量的每一行进行相加

    visualization(center,clusterAssment, dataset)

    # 返回聚类中心center(k,2)的矩阵,每行是坐标
    # 返回聚类结果clusterAssment(size,2)的矩阵,每行第一列是归属类的序号,第二列是点到中心的距离
    return center, clusterAssment


def main():
    _, _ = kmeans(200, 0, 10, 4)


if __name__ == "__main__":
    main()

聚类结果:
图1

sklearn中的k-means算法

sklearn库中有封装好的k-means算法

# -*- coding:utf-8 -*-

import random
import numpy as np
import matplotlib.pylab as plt
from sklearn.cluster import KMeans


def create_the_dataset(size, min, max):
    # 随机生成数据集,size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值
    dataset = []
    sub_dataset = []
    for i in range(size):
        sub_dataset.append(random.uniform(min, max))
        sub_dataset.append(random.uniform(min, max))
        dataset.append(sub_dataset)
        sub_dataset = []

    dataset = np.mat(dataset)
    # 将列表变成矩阵
    # 数据集是(size,2)的矩阵

    return dataset


def kmeans(size, min, max, k):
    # k-means算法的实现
    # size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值,k是选取的聚类中心的个数
    dataset = create_the_dataset(size, min, max)
    # 生成数据集
    y_pred = KMeans(n_clusters=k).fit_predict(dataset)
    plt.scatter(dataset[:, 0].tolist(), dataset[:, 1].tolist(), c=y_pred)
    plt.savefig("k-means.png")
    plt.show()


def main():
    kmeans(200, 0, 10, 4)


if __name__ == "__main__":
    main()

聚类结果:
在这里插入图片描述

参数:

sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1)
  • n_clusters:聚类中心个数的选择
  • init:用"k-means++"还是用"random"初始化聚类中心
  • n_init:跑k-means的次数,最后选择最好的结果作为最后结果
  • max_iter:跑一次k-means的最大迭代次数
  • random_state: 如果给出整数,随机初始化聚类中心将固定种子

使用方法:

  • fit(X[, y]):Compute k-means clustering.
  • fit_predict(X[, y]):Compute cluster centers and predict cluster index for each sample.
  • fit_transform(X[, y]):Compute clustering and transform X to cluster-distance space.
  • get_params([deep]):Get parameters for this estimator.
  • predict(X):Predict the closest cluster each sample in X belongs to.
  • score(X[, y]):Opposite of the value of X on the K-means objective.
  • set_params(**params):Set the parameters of this estimator.
  • transform(X[, y]):Transform X to a cluster-distance space.

官方文档:http://lijiancheng0614.github.io/scikit-learn/modules/generated/sklearn.cluster.KMeans.html

关于k-means++:

k-means++算法选择初始聚类中心的基本思想就是:初始的聚类中心之间的相互距离要尽可能的远

  1. 从输入的数据点集合中随机选择一个点作为第一个聚类中心
  2. 对于数据集中的每一个点x,计算它与最近聚类中心(指已选择的聚类中心)的距离D(x)
  3. 选择一个新的数据点作为新的聚类中心,选择的原则是:D(x)较大的点,被选取作为聚类中心的概率较大
  4. 重复2和3直到k个聚类中心被选出来
  5. 利用这k个初始的聚类中心来运行标准的k-means算法

参考来源:https://blog.csdn.net/chlele0105/article/details/12997391

结语

如果您有修改意见或问题,欢迎留言或者通过邮箱和我联系。
手打很辛苦,如果我的文章对您有帮助,转载请注明出处。

发布了57 篇原创文章 · 获赞 19 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Zhang_Chen_/article/details/91050699