sklearn K-Means 算法的调用

本文介绍 Python 语言调用 sklearn 包中 K-Means 算法实现聚类的方法。


在 sklearn 包中,常用的 K-Means 方法有两种:KMeans 和 MiniBatchKMeans

两种方法的参数相似,常用参数如下:
n_clusters:聚类数量,即 k 值,默认为 8
init:初始化聚类中心的方法,如需自定义设置,则传入 ndarray 格式的参数
n_init:用不同的初始化聚类中心运行算法的次数,默认为 10,如自定义设置初始聚类中心,则置为 1
max_iter:最大迭代次数,默认为 300
batch_size:(仅 MiniBatchKMeans)批次大小,默认为 100
verbose:是否打印日志,默认为否

注:自定义设置初始聚类中心的一个用处是去除算法的随机性,即防止每次运行结果不一样。


随机生成一组算例,给出代码和可视化结果作为示例:

基本参数:

NUM_POINT = 500  # 点的总数
RAN_COO = (0, 100)  # 坐标范围

NUM_CLUSTER = 20  # 聚类数量
MAX_ITERATION = 5000  # 最大迭代次数
NUM_BATCH = 10  # 批次数量

随机生成算例:

import random
import pandas as pd

edge_width= 1  # 坐标边界宽度

random.seed(612)
list_coo_x = [random.randint(RAN_COO[0] + edge_width, RAN_COO[1] - edge_width) for _ in range(NUM_POINT)]
list_coo_y = [random.randint(RAN_COO[0] + edge_width, RAN_COO[1] - edge_width) for _ in range(NUM_POINT)]
df_point = pd.DataFrame({'x': list_coo_x, 'y': list_coo_y})

模型初始化:

from sklearn.cluster import KMeans, MiniBatchKMeans

# 方式 1: KMeans 方法;初始聚类中心的生成方式为默认
model = KMeans(n_clusters=NUM_CLUSTER, max_iter=MAX_ITERATION, verbose=True)

# 方式 2: MiniBatchKMeans 方法;初始聚类中心的生成方式为默认
model = MiniBatchKMeans(n_clusters=NUM_CLUSTER, max_iter=MAX_ITERATION, batch_size=round(NUM_POINT / NUM_BATCH), verbose=True)

# 方式 3: KMeans 方法;自定义初始聚类中心
model = KMeans(n_clusters=num_cluster_adjust, init=init, n_init=1, max_iter=MAX_ITERATION, verbose=True)

# 方式 4: MiniBatchKMeans 方法;自定义初始聚类中心
model = MiniBatchKMeans(n_clusters=NUM_CLUSTER, init=init, n_init=1, max_iter=MAX_ITERATION, batch_size=round(NUM_POINT / NUM_BATCH), verbose=True)

(附)一种自定义初始聚类中心的方法:

思路:将点集所在的矩形区域划分为格子,取每个小格的中心作为初始聚类中心

from typing import Tuple, List
import math

def get_init_centres(num_cluster: int, ran_x: Tuple[float, float], ran_y: Tuple[float, float],
                     per_adjust_n: float = 0.05) -> Tuple[int, List[Tuple[float, float]]]:
    """
    获取初始聚类中心的坐标

    :param num_cluster:  聚类数量
    :param ran_x:  区域的横坐标范围
    :param ran_y:  区域的纵坐标范围
    :param per_adjust_n:  聚类数量允许调整的百分比,默认0.05

    :return: num_cluster_adjust:  调整后的聚类数量
    :return: list_pos_centres:  初始聚类中心的坐标列表
    """

    print(">> 获取初始聚类中心的坐标,开始")

    def get_nearest_divisors(number: int) -> Tuple[int, int]:
        """
        获取一个整数最相邻的两个约数

        :param number:  一个大的整数

        :return: a:  较小的约数
        :return: b:  较大的约数
        """

        init_value = int(math.sqrt(number))
        a, b = init_value, init_value

        while (a * b != number) and (a > 0):
            if a * b < number:
                b += 1
            else:
                a -= 1

        return a, b

    # 横坐标范围和纵坐标范围,哪一个为长边
    if_len_x = True if ran_x[1] - ran_x[0] >= ran_y[1] - ran_y[0] else False
    len_x_y = ran_x[1] - ran_x[0] if if_len_x else ran_y[1] - ran_y[0]
    wid_x_y = ran_y[1] - ran_y[0] if if_len_x else ran_x[1] - ran_x[0]

    # 聚类数量的可调整范围
    lb_num_cluster = math.ceil((1 - per_adjust_n) * num_cluster)
    ub_num_cluster = math.floor((1 + per_adjust_n) * num_cluster)

    # 调整聚类数量,使其尽可能符合坐标范围的长宽比
    len_cluster, wid_cluster = num_cluster, 1
    diff = 1
    for n in range(lb_num_cluster, ub_num_cluster + 1):
        tmp_wid, tmp_len = get_nearest_divisors(n)
        tmp_diff = abs(tmp_wid / tmp_len - wid_x_y / len_x_y)
        if tmp_diff < diff:
            len_cluster, wid_cluster = tmp_len, tmp_wid
            diff = tmp_diff

    # 结果输出:调整后的聚类数量
    num_cluster_adjust = len_cluster * wid_cluster

    # 结果输出:初始聚类中心的坐标列表
    if if_len_x:
        list_x_centres = [ran_x[0] + len_x_y / (2 * len_cluster) + len_x_y / len_cluster * i 
                          for i in range(len_cluster)]
        list_y_centres = [ran_y[0] + wid_x_y / (2 * wid_cluster) + wid_x_y / wid_cluster * j 
                          for j in range(wid_cluster)]
    else:
        list_x_centres = [ran_x[0] + wid_x_y / (2 * wid_cluster) + wid_x_y / wid_cluster * j 
                          for j in range(wid_cluster)]
        list_y_centres = [ran_y[0] + len_x_y / (2 * len_cluster) + len_x_y / len_cluster * i 
                          for i in range(len_cluster)]
    list_pos_centres = [(x, y) for x in list_x_centres for y in list_y_centres]

    print("<< 获取初始聚类中心的坐标,结束")

    return num_cluster_adjust, list_pos_centres
import numpy as np

ran_x, ran_y = (min(df_point['x']), max(df_point['x'])), (min(df_point['y']), max(df_point['y']))
num_cluster_adjust, list_centre_initial = get_init_centres(num_cluster=NUM_CLUSTER, ran_x=ran_x, ran_y=ran_y)
if num_cluster_adjust != NUM_CLUSTER:
    print("聚类数量由 {0} 调整为 {1}".format(NUM_CLUSTER, num_cluster_adjust), '\n')
init = np.array(list_centre_initial, dtype=np.float64)  # 自定义聚类中心的格式

算法运行:

model.fit(df_point)

结果处理:

df_centre = pd.DataFrame(model.cluster_centers_, columns=['x', 'y']).reset_index()
se_category = pd.Series(model.labels_, index=df_point.index)
df_res = pd.concat([df_point, se_category], axis=1)
df_res.rename(columns={0: "category"}, inplace=True)
print("最终聚类数量: {}".format(len(set(df_res["category"]))), '\n')

结果可视化:

from matplotlib import pyplot as plt

list_color = ["red", "green", "blue", "orange", "purple", 'darkorange', 'deepskyblue', 'lime', 'fuchsia', "grey"]
list_marker = ['.', 'o', 's', 'x', '+', '*', 'p', 'v', '^', '<', '>', '1', '2', '3', '4']

i = 0
for c, df in df_res.groupby("category"):
    x, y = df['x'], df['y']
    plt.scatter(x=x, y=y, c=list_color[i % len(list_color)], marker=list_marker[i % len(list_marker)], alpha=1)
    i += 1

plt.xlim(RAN_COO[0], RAN_COO[1])
plt.ylim(RAN_COO[0], RAN_COO[1])



上述算例的可视化结果:


方式 1: KMeans 方法;初始聚类中心的生成方式为默认
sklearn K-Means 算法的调用_第1张图片
方式 2:MiniBatchKMeans 方法;初始聚类中心的生成方式为默认
sklearn K-Means 算法的调用_第2张图片
方式 3: KMeans 方法;自定义初始聚类中心
sklearn K-Means 算法的调用_第3张图片
方式 4: MiniBatchKMeans 方法;自定义初始聚类中心
sklearn K-Means 算法的调用_第4张图片

你可能感兴趣的:(机器学习)