kmeans手写实现与sklearn接口

kmeans手写实现与sklearn接口

kmeans简介

K 均值聚类是最基础的一种聚类方法。它是一种迭代求解的聚类分析算法。

kmeans的迭代步骤

  1. 给各个簇中心 μ 1 , … , μ c \mu_1,\dots,\mu_c μ1,,μc 以适当的初值;

  2. 更新样本 x 1 , … , x n x_1,\dots,x_n x1,,xn 对应的簇标签 y 1 , … , y n y_1,\dots,y_n y1,,yn
    y i ← a r g m i n y ∈ { 1 , … , c } ∣ ∣ x i − μ y ∣ ∣ 2 ,     i = 1 , … , n y_i\leftarrow argmin_{y\in \{1,\dots,c\}}||x_i-\mu_y||^2,\ \ \ i=1,\dots,n yiargminy{1,,c}∣∣xiμy2,   i=1,,n

  3. 更新各个簇中心 μ 1 , … , μ c \mu_1,\dots,\mu_c μ1,,μc
    μ y ← 1 n y ∑ i : y i = y x i ,     y = 1 , … , c \mu_y\leftarrow \frac{1}{n_y}\sum_{i:y_i=y}x_i,\ \ \ y=1,\dots,c μyny1i:yi=yxi,   y=1,,c
    其中, n y n_y ny 为属于簇 y y y 的类别总数

  4. 重复上述步骤2, 3,直到簇标签不再变化(变化足够小),达到收敛精度为止

优缺点

优点

  1. 算法快速、简单;
  2. 对大数据集有较高的效率并且是可伸缩性的;
  3. 时间复杂度近于线性,而且适合挖掘大规模数据集。K-Means聚类算法的时间复杂度是O(n×k×t) ,其中n代表数据集中对象的数量,t代表着算法迭代的次数,k代表着簇的数目

缺点

  1. 在k-measn算法中K是事先给定的,但是K值的选定是非常难以估计的。
  2. 在 K-means 算法中,首先需要根据初始聚类中心来确定一个初始划分,然后对初始划分进行优化。这个初始聚类中心的选择对聚类结果有较大的影响,一旦初始值选择的不好,可能无法得到有效的聚类结果,这也成为 K-means算法的一个主要问题。
  3. 当数据量很大时,算法的开销是非常大的。

kmeans算法的改进

  • kmeans++
  • 二分Kmeans
    • 分解最大 SSE (误差平方和)的簇
    • 合并距离最小的簇 或者 合并SSE增幅最小的两个簇。

手写实现

伪代码:

创建 k 个点作为起始质心 (随机选择):
    当任意一个点的簇分配结果发生改变的时候:
        对数据集中的每个数据点:
           对每个质心:
                计算质心与数据点之间的距离
           将数据点分配到距其最近的簇
       对每一个簇:
           求出均值并将其更新为质心

Python实现:

import numpy as np

def kmeans(data, n_clusters, tolerence):
    n_samples = data.shape[0]
    sample_asign = np.zeros((n_samples, 2))
    cluster_centers = data[: n_clusters, :]
    isChanged = True

    epoch_cnt = 0
    while isChanged:
        epoch_cnt += 1
        isChanged = False
        # 更新每个样本点所属于的类
        for sample_index in range(n_samples):
            min_dist = np.inf
            min_index = 0
            for cluster_index in range(n_clusters):
                dist = np.linalg.norm(data[sample_index, :] - cluster_centers[cluster_index, :])
                if dist < min_dist:
                    min_dist = dist
                    min_index = cluster_index

            sample_asign[sample_index, :] = min_dist, min_index

        # 更新每个聚类中心
        for cluster_index in range(n_clusters):
            new_cluster_samples = data[ sample_asign[:, 1] == cluster_index ]
            new_center = np.mean(new_cluster_samples, axis=0)

            cluster_center_diff = np.linalg.norm( new_center - cluster_centers[cluster_index, :] )
            cluster_centers[cluster_index, :] = new_center
            if cluster_center_diff > tolerence:
                isChanged = True
    print(f"epoch count: {epoch_cnt}")
    return cluster_centers

if __name__ == '__main__':
    n_samples = 512
    data_dim = 3
    n_clusters = 4
    data = np.random.randn(n_samples, data_dim)
    tol = 1e-12

    centers = kmeans(data, n_clusters, tol)
    print(centers)

sklearn接口

kmeans 手写实现主要还是为了理解算法,在实际应用中,我们一般调 sklearn 的包就好了。

class sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, verbose=0, random_state=None, copy_x=True, algorithm='lloyd')

类初始化参数

  • init:指定初始化聚类中心的方法。可以是 kmeans++ (默认),random 随机选取,或者是一个形状为 (n_clusters, n_features) 的数组,直接将该数组作为初始的聚类中心。
  • n_init:使用不同质心 (centeroid) 种子运行k -means 算法的次数。最终结果将是 inertia 最佳时的输出。整型,默认为 10。
  • max_iter:kmeans 算法单词运行的最大迭代数。整型,默认 300。
  • tol:关于两次连续迭代的聚类中心差异的 Frobenius 范数的相对容忍度,小于该值认为收敛。浮点数。
  • verbose:是否打印迭代过程中的输出。整型,默认为 0。
  • random_state:决定初始聚类中心的随机数种子。整型。
  • copy_x:在预先计算距离时,首先将数据居中在数值上更准确。 如果 copy_x 为 True(默认),则不修改原始数据。 如果为 False,则修改原始数据,并在函数返回之前放回,但通过减去再添加数据均值可能会引入小的数值差异。 请注意,如果原始数据不是 C 连续的,即使 copy_x 为 False,也会进行复制。 如果原始数据是稀疏的,但不是 CSR 格式,即使 copy_x 为 False,也会进行复制。
  • algorithm:要使用的 K-means 算法。 默认是经典的 EM 风格算法 “lloyd”。可选项有:“lloyd”, “elkan”, “auto”, “full”。

类属性

  • cluster_centers_:聚类中心的坐标,是一个形状为 (n_clusters, n_features) 的数组。如果算法完全收敛,则与 labels_ 一致。
  • labels_:每个点的标签,形状为 (n_clusters, ) 。
  • inertia_:样本到其最近聚类中心的平方距离总和,如果给了权重的话会计算加权和。浮点数。
  • n_features_in_:在运行 fit 方法时见到的特征数,整型、
  • feature_names_in_:在运行 fit 方法时见到到的特征名称。只有当 X 的要素名称均为字符串时才定义。形状为 (n_features_in_, ) 的数组。

类方法

函数签名 说明
fit(X[, y, sample_weight]) 计算 kmeans 聚类
fit_predict(X[, y, sample_weight]) 计算 kmeans 聚类并预测每个样本的簇序号
fit_transform(X[, y, sample_weight]) 计算 kmeans 聚类并将 X 转换到聚类距离空间
get_feature_names_out([input_features]) 获取转换的输出特征名称
get_params([deep]) 获取 estimator 的参数
predict(X[, sample_weight]) 预测 X 中每个样本所属于的簇
score(X[, y, sample_weight]) (看起来是评估模型的准确率)
set_params(**params) 设置 estimator 的参数
transform(X) 将 X 转换到聚类距离空间

模型保存与加载

需要通过 joblib 来保存,安装:

pip install joblib

保存/加载模型

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import joblib

x, y = make_blobs(n_samples=1000, n_features=4, centers=[[-1, -1], [0, 0], [1, 1], [2, 2]], cluster_std=[0.4, 0.2, 0.2, 0.4], random_state=42)
model = KMeans(n_clusters=6)
model.fit(x, y)
print(model.cluster_centers_)
# 保存模型
joblib.dump(model, 'kmeans_model.pkl')
# 加载模型
model = joblib.load('kmeans_model.pkl')
print(model.cluster_centers_)

Ref

  1. 图解机器学习——杉山将
  2. sklearn官方文档
  3. k-means原理与实现

你可能感兴趣的:(机器学习,kmeans,sklearn,聚类)