机器学习-聚类算法

手写笔记

请添加图片描述

KMeans 算法实现

""" @File   : k_means
    @Author : BabyMuu
    @Time   : 2022/4/16 21:54
"""
import numpy as np

class KMeans:
    def __init__(self, data, n_clusters, random_state=None):
        self.data = data
        self.n_clusters = n_clusters
        self.n_examples = self.data.shape[0]
        self.random_state = random_state

    def train(self, max_iter=50):
        # 1, 随机初始化中心点位置
        centroids = self.center_init()
        # 2, 开始训练, 预设一个样本数据长度的空数组
        closest_centroid_ids = np.empty((self.n_examples, 1))
        for _ in range(max_iter):
            # 3 得到每一个样本点到k个中心点的距离, 返回样本点到最近的中心点的中心点id
            closest_centroid_ids = self.centroids_find_closest(centroids)
            # 4 更新中心点位置
            centroids = self.centroids_update(closest_centroid_ids)
        return centroids, closest_centroid_ids

    def center_init(self):
        # 1 获取随机数组
        np.random.seed(self.random_state)
        random_ids = np.random.permutation(self.n_examples)
        # 2 获取中心点
        centroids = self.data[random_ids[:self.n_clusters], :]
        # 3 返回数据
        return centroids

    def centroids_find_closest(self, centroid):
        n_centroids = centroid.shape[0]
        closest_centroids_ids = np.zeros((self.n_examples, 1))
        for examples_index in range(self.n_examples):
            # 计算每一个点的到各个中心点的距离
            distance = np.zeros((n_centroids, 1))
            for centroid_index in range(n_centroids):
                distance_diff = self.data[examples_index, :] - centroid[centroid_index, :]
                distance[centroid_index] = np.sum(distance_diff ** 2)
            # 获取距离最近的那个中心点的id
            closest_centroids_ids[examples_index] = np.argmin(distance)
        return closest_centroids_ids

    def centroids_update(self, closest_centroid_ids):
        # 1 获取特征个数
        n_features = self.data.shape[1]
        # 2 初始化中心点数据, 暂时以0填充, 该数值不参与运算
        centroids = np.zeros((self.n_clusters, n_features))
        # 3 遍历每一个中心点
        for centroid_id in range(self.n_clusters):
            # 找到当前中心点聚类中的样本点索引
            closest_ids = closest_centroid_ids == centroid_id
            # 将当前聚类范围的样本的数据值取均值, 生成新的中心点
            centroids[centroid_id] = np.mean(self.data[closest_ids.flatten(), :], axis=0)
        return centroids

聚类结果可视化

""" @File   : draw_kmeans
    @Author : BabyMuu
    @Time   : 2022/5/8 12:42
"""
import numpy as np
import pandas as pd
from scipy.cluster.vq import vq

def draw_kmeans(features, centroids, plt, k, title=None):
    # 添加中文字体支持
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    # 打印聚类中心
    code, distance = vq(features, centroids)
    unique_code = pd.Series(code).unique()
    for i in unique_code:
        ndx = np.where(code == i)[0]
        plt.plot(features[ndx, 0], features[ndx, 1], '*')
    plt.plot(centroids[:, 0], centroids[:, 1], 'bo')
    if title:
        plt.title(title)
    else:
        plt.title(f'2维数据点聚类 k = {k}')

简单测试

""" @File   : Demo
    @Author : BabyMuu
    @Time   : 2022/5/8 12:15
# """
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from numpy.random import randn
from sklearn.datasets import make_circles, make_moons

from k_means import KMeans
from handwritten_algorithm_model.template.draw.draw_kmeans import draw_kmeans

# 添加中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
# 静态数据
FIGSIZE = (16, 12)
# 随机生成数据 1 球形数据
class1 = 12.5 + 5.6 * np.random.randn(500, 2)
class2 = np.random.randn(500, 2)
class3 = 5.6 * np.random.randn(500, 2)
# 提取数据特征点
features = np.vstack((class1, class2, class3))

# 随机生成数据 2 环状数据
features_2, target_2 = make_circles(n_samples=1000, factor=0.5, noise=0.1)

# 随机生成数据 3 半环形数据
features_3, target_3 = make_moons(n_samples=1000, noise=0.1)
plt.figure(figsize=FIGSIZE)
feature_index = 0
title = ['球形', '环形', '半环形']
for feature in (features, features_2, features_3):
    for i in range(2, 6):
        # 初始化模型
        kmeans = KMeans(feature, i)
        # 训练模型并得到聚类结果
        centroids, variance = kmeans.train()
        # 画聚类结果图
        plt.subplot(3, 4, (i - 1) + feature_index * 4)
        plot_title = f'{title[feature_index]}簇, k={i}'
        draw_kmeans(feature, centroids, plt, i, plot_title)
    feature_index += 1
plt.show()

可视化结果

聚类结果展示

聚类结果分析

  • 聚类的好坏与样本簇的形状有着很大的关系, 无法正确分辨环型簇, 半环型簇等非球形簇的形状样本
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值