【机器学习】聚类(一):原型聚类:K-means聚类

文章目录

  • 一、实验介绍
    • 1. 算法流程
    • 2. 算法解释
    • 3. 算法特点
    • 4. 应用场景
    • 5. 注意事项
  • 二、实验环境
    • 1. 配置虚拟环境
    • 2. 库版本介绍
  • 三、实验内容
    • 0. 导入必要的库
    • 1. Kmeans类
      • a. 构造函数
      • b. 闵可夫斯基距离
      • c. 初始化簇心
      • d. K-means聚类
      • e. 聚类结果可视化
    • 2. 辅助函数
    • 3. 主函数
      • a. 命令行界面 (CLI)
      • b. 数据加载
      • c. 模型训练及可视化
    • 4. 运行脚本的命令
    • 5. 代码整合

  原型聚类中的K均值算法是一种常用的聚类方法,该算法的目标是通过迭代过程找到数据集的簇划分,使得每个簇内的样本与簇内均值的平方误差最小化。这一过程通过不断迭代更新簇的均值来实现。

一、实验介绍

在这里插入图片描述

1. 算法流程

  1. 初始化: 从样本集中随机选择k个样本作为初始均值向量。
  2. 迭代过程: 重复以下步骤直至均值向量不再更新:
    • 对每个样本计算与各均值向量的距离。
    • 将样本划分到距离最近的均值向量所对应的簇。
    • 更新每个簇的均值向量为该簇内样本的平均值。
  3. 输出: 返回最终的簇划分。

2. 算法解释

  • 步骤1中,通过随机选择初始化k个均值向量。
  • 步骤2中,通过计算样本与均值向量的距离,将每个样本分配到最近的簇。然后,更新每个簇的均值向量为该簇内样本的平均值。
  • 算法通过迭代更新,不断优化簇内样本与均值向量的相似度,最终得到较好的聚类结果。

3. 算法特点

  • K均值算法是一种贪心算法,通过局部最优解逐步逼近全局最优解。
  • 由于需要对每个样本与均值向量的距离进行计算,算法复杂度较高。
  • 对于大型数据集和高维数据,K均值算法的效果可能受到影响。

4. 应用场景

  • K均值算法适用于样本集可以被均值向量较好表示的情况,特别是当簇呈现球形或近似球形分布时效果较好。
  • 在图像分割、用户行为分析等领域广泛应用。

5. 注意事项

  • 对于K均值算法,初始均值向量的选择可能影响最终聚类结果,因此有时需要多次运行算法,选择最优的结果。
  • 算法对异常值敏感,可能导致簇的均值向量被拉向异常值,因此在处理异常值时需要谨慎。

二、实验环境

1. 配置虚拟环境

conda create -n ML python==3.9
conda activate ML
conda install scikit-learn matplotlib seaborn

2. 库版本介绍

软件包本实验版本
matplotlib3.5.2
numpy1.21.5
python3.9.13
scikit-learn1.0.2
seaborn0.11.2

三、实验内容

0. 导入必要的库

import numpy as np
import random
import seaborn as sns
import matplotlib.pyplot as plt
import argparse

1. Kmeans类

  • __init__ :初始化K均值聚类的参数,包括聚类数目 k、数据 data、初始化模式 mode(默认为 “random”)、最大迭代次数 max_iters、闵可夫斯基距离的阶数 p、随机种子 seed等。
  • minkowski_distance 函数:计算两个样本点之间的闵可夫斯基距离。
  • center_init 函数:根据指定的模式初始化聚类中心。
  • fit 方法:执行K均值聚类的迭代过程,包括分配样本到最近的簇、更新簇中心,直到满足停止条件。
  • visualization 函数:使用Seaborn和Matplotlib可视化聚类结果。

a. 构造函数

class Kmeans(object):def __init__(self, k, data: np.ndarray, mode="random", max_iters=0, p=2, seed=0):self.k = kself.data = dataself.mode = modeself.max_iter = max_iters if max_iters > 0 else int(1e8)self.p = pself.seed = seedself.centers = Noneself.clu_idx = np.zeros(len(self.data), dtype=np.int32)  # 样本的分类簇self.clu_dist = np.zeros(len(self.data), dtype=np.float64)  # 样本与簇心的距离
  • 参数:
    • 聚类数目 k
    • 数据集 data
    • 初始化模式 mode
    • 最大迭代次数 max_iters
    • 闵可夫斯基距离的阶数 p 以及随机种子 seed
  • 初始化类的上述属性,此外
    • self.centers 被初始化为 None,表示簇心尚未计算
    • self.clu_idxself.clu_dist 被初始化为全零数组,表示每个样本的分类簇和与簇心的距离。

b. 闵可夫斯基距离

    def minkowski_distance(self, x, y=0):return np.linalg.norm(x - y, ord=self.p)
  • 使用了NumPy的 linalg.norm 函数,其中 ord 参数用于指定距离的阶数。

c. 初始化簇心

    def center_init(self):random.seed(self.seed)if self.mode == "random":ids = random.sample(range(len(self.data)), k=self.k)  # 随机抽取k个样本下标self.centers = self.data[ids]  # 选取k个样本作为簇中心else:ids = [random.randint(0, self.data.shape[0])]for _ in range(1, self.k):max_idx = 0max_dis = 0for i, x in enumerate(self.data):if i in ids:continuedis = 0for y in self.data[ids]:dis += self.minkowski_distance(x - y)if max_dis < dis:max_dis = dismax_idx = iids.append(max_idx)self.centers = self.data[ids]
  • 根据指定的初始化模式,选择随机样本或使用 “far” 模式。
    • 在 “random” 模式下,通过随机抽样选择 k 个样本作为簇心;
    • 在 “far” 模式下,通过计算每个样本到已选簇心的距离之和,选择距离总和最大的样本作为下一个簇心。

d. K-means聚类

    def fit(self):self.center_init()  # 簇心初始化for _ in range(self.max_iter):flag = False  # 判断是否有样本被重新分类# 遍历每个样本for i, x in enumerate(self.data):min_idx = -1  # 最近簇心下标min_dist = np.inf  # 最小距离for j, y in enumerate(self.centers):  # 遍历每个簇,计算与该样本的距离# 计算样本i到簇j的距离distdist = self.minkowski_distance(x, y)if min_dist > dist:min_dist = distmin_idx = jif self.clu_idx[i] != min_idx:# 有样本改变分类簇,需要继续迭代更新簇心flag = True# 记录样本i与簇的最小距离min_dist,及对应簇的下标min_idxself.clu_idx[i] = min_idxself.clu_dist[i] = min_dist# 样本的簇划分好之后,用样本均值更新簇心for i in range(self.k):x = self.data[self.clu_idx == i]# 用样本均值更新簇心self.centers[i] = np.mean(x, axis=0)if not flag:break
  • 在每次迭代中
    • 遍历每个样本,计算其到各个簇心的距离,将样本分配到距离最近的簇中。
    • 更新每个簇的均值(簇心)为该簇内所有样本的平均值。
  • 上述过程迭代进行,直到满足停止条件(样本不再重新分配到不同的簇)或达到最大迭代次数。

e. 聚类结果可视化

    def visualization(self, k=3):current_palette = sns.color_palette()sns.set_theme(context="talk", palette=current_palette)for i in range(self.k):x = self.data[self.clu_idx == i]sns.scatterplot(x=x[:, 0], y=x[:, 1], alpha=0.8)sns.scatterplot(x=self.centers[:, 0], y=self.centers[:, 1], marker="+", s=500)plt.title("k=" + str(k))plt.show()

2. 辅助函数

def order_type(v: str):if v.lower() in ("-inf", "inf"):return -np.inf if v.startswith("-") else np.infelse:try:return float(v)except ValueError:raise argparse.ArgumentTypeError("Unsupported value encountered")def mode_type(v: str):if v.lower() in ("random", "far"):return v.lower()else:raise argparse.ArgumentTypeError("Unsupported value encountered")
  • order_type 函数:用于处理命令行参数中的 -p(距离测量参数),将字符串转换为浮点数。
  • mode_type 函数:用于处理命令行参数中的 --mode(初始化模式参数),将字符串转换为合法的初始化模式。

3. 主函数

a. 命令行界面 (CLI)

  • 使用 argparse 解析命令行参数
    parser = argparse.ArgumentParser(description="Kmeans Demo")parser.add_argument("-k", type=int, default=3, help="The number of clusters")parser.add_argument("--mode", type=mode_type, default="random", help="Initial centroid selection")parser.add_argument("-m", "--max-iters", type=int, default=40, help="Maximum iterations")parser.add_argument("-p", type=order_type, default=2., help="Distance measurement")parser.add_argument("--seed", type=int, default=0, help="Random seed")parser.add_argument("--dataset", type=str, default="./kmeans.2.txt", help="Path to dataset")args = parser.parse_args()

b. 数据加载

  • 从指定路径加载数据集。
	dataset = np.loadtxt(args.dataset)

在这里插入图片描述

c. 模型训练及可视化

	model = Kmeans(k=args.k, data=dataset, mode=args.mode, max_iters=args.max_iters, p=args.p,seed=args.seed)model.fit()# 聚类结果可视化model.visualization(k=args.k)

4. 运行脚本的命令

  • 通过命令行传递参数来运行脚本,指定聚类数目、初始化模式、最大迭代次数等。
python kmeans.py -k 3 --mode random -m 40 -p 2 --seed 0 --dataset ./kmeans.2.txt

在这里插入图片描述

5. 代码整合

import numpy as np
import random
import seaborn as sns
import matplotlib.pyplot as plt
import argparseclass Kmeans(object):def __init__(self, k, data: np.ndarray, mode="random", max_iters=0, p=2, seed=0):self.k = kself.data = dataself.mode = modeself.max_iter = max_iters if max_iters > 0 else int(1e8)self.p = pself.seed = seedself.centers = Noneself.clu_idx = np.zeros(len(self.data), dtype=np.int32)  # 样本的分类簇self.clu_dist = np.zeros(len(self.data), dtype=np.float64)  # 样本与簇心的距离def minkowski_distance(self, x, y=0):return np.linalg.norm(x - y, ord=self.p)# 簇心初始化def center_init(self):random.seed(self.seed)if self.mode == "random":ids = random.sample(range(len(self.data)), k=self.k)  # 随机抽取k个样本下标self.centers = self.data[ids]  # 选取k个样本作为簇中心else:ids = [random.randint(0, self.data.shape[0])]for _ in range(1, self.k):max_idx = 0max_dis = 0for i, x in enumerate(self.data):if i in ids:continuedis = 0for y in self.data[ids]:dis += self.minkowski_distance(x - y)if max_dis < dis:max_dis = dismax_idx = iids.append(max_idx)self.centers = self.data[ids]def fit(self):self.center_init()  # 簇心初始化for _ in range(self.max_iter):flag = False  # 判断是否有样本被重新分类# 遍历每个样本for i, x in enumerate(self.data):min_idx = -1  # 最近簇心下标min_dist = np.inf  # 最小距离for j, y in enumerate(self.centers):  # 遍历每个簇,计算与该样本的距离# 计算样本i到簇j的距离distdist = self.minkowski_distance(x, y)if min_dist > dist:min_dist = distmin_idx = jif self.clu_idx[i] != min_idx:# 有样本改变分类簇,需要继续迭代更新簇心flag = True# 记录样本i与簇的最小距离min_dist,及对应簇的下标min_idxself.clu_idx[i] = min_idxself.clu_dist[i] = min_dist# 样本的簇划分好之后,用样本均值更新簇心for i in range(self.k):x = self.data[self.clu_idx == i]# 用样本均值更新簇心self.centers[i] = np.mean(x, axis=0)if not flag:breakdef visualization(self, k=3):current_palette = sns.color_palette()sns.set_theme(context="talk", palette=current_palette)for i in range(self.k):x = self.data[self.clu_idx == i]sns.scatterplot(x=x[:, 0], y=x[:, 1], alpha=0.8)sns.scatterplot(x=self.centers[:, 0], y=self.centers[:, 1], marker="+", s=500)plt.title("k=" + str(k))plt.show()def order_type(v: str):if v.lower() in ("-inf", "inf"):return -np.inf if v.startswith("-") else np.infelse:try:return float(v)except ValueError:raise argparse.ArgumentTypeError("Unsupported value encountered")def mode_type(v: str):if v.lower() in ("random", "far"):return v.lower()else:raise argparse.ArgumentTypeError("Unsupported value encountered")if __name__ == '__main__':parser = argparse.ArgumentParser(description="Kmeans Demo")parser.add_argument("-k", type=int, default=3, help="The number of clusters")parser.add_argument("--mode", type=mode_type, default="random", help="Initial centroid selection")parser.add_argument("-m", "--max-iters", type=int, default=40, help="Maximum iterations")parser.add_argument("-p", type=order_type, default=2., help="Distance measurement")parser.add_argument("--seed", type=int, default=0, help="Random seed")parser.add_argument("--dataset", type=str, default="./kmeans.2.txt", help="Path to dataset")args = parser.parse_args()dataset = np.loadtxt(args.dataset)model = Kmeans(k=args.k, data=dataset, mode=args.mode, max_iters=args.max_iters, p=args.p,seed=args.seed)  # args.seed)model.fit()# 聚类结果可视化model.visualization(k=args.k)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/167820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数组题目: 665. 非递减数列、453. 最小移动次数使数组元素相等、283. 移动零、189. 旋转数组、396. 旋转函数

665. 非递减数列 题解&#xff1a; 题目要求一个非递减数列&#xff0c;我们可以考虑需要更改的情况&#xff1a; nums {4, 2, 5} 对于这个nums&#xff0c;由于2的出现导致非递减&#xff0c;更改的情况就是要么4调到<2&#xff0c;要么2调到4,5. nums {1, 4, 2, 5} …

人工智能-注意力机制之注意力汇聚:Nadaraya-Watson 核回归

查询&#xff08;自主提示&#xff09;和键&#xff08;非自主提示&#xff09;之间的交互形成了注意力汇聚&#xff1b; 注意力汇聚有选择地聚合了值&#xff08;感官输入&#xff09;以生成最终的输出。 本节将介绍注意力汇聚的更多细节&#xff0c; 以便从宏观上了解注意力机…

Lubuntu 23.10用户可使用LXQt 1.4桌面

导读在众多 Lubuntu 用户的要求下&#xff0c;Lubuntu 开发人员决定将 LXQt 1.4 桌面环境向后移植到最新的 Lubuntu 23.10 &#xff08;Mantic Minotaur&#xff09; 版本。 是的&#xff0c;您没看错&#xff0c;您现在可以使用官方的 Lubuntu Backports PPA&#xff08;个人软…

黑马点评笔记 分布式锁

文章目录 分布式锁基本原理和实现方式对比Redis分布式锁的实现核心思路实现分布式锁版本一Redis分布式锁误删情况说明解决Redis分布式锁误删问题分布式锁的原子性问题分布式锁-Redission分布式锁-redission可重入锁原理分布式锁-redission锁重试和WatchDog机制分布式锁-redissi…

01、Tensorflow实现二元手写数字识别

01、Tensorflow实现二元手写数字识别&#xff08;二分类问题&#xff09; 开始学习机器学习啦&#xff0c;已经把吴恩达的课全部刷完了&#xff0c;现在开始熟悉一下复现代码。对这个手写数字实部比较感兴趣&#xff0c;作为入门的素材非常合适。 基于Tensorflow 2.10.0 1、…

数据丢失预防措施包括什么

数据丢失预防措施是保护企业或个人重要数据的重要手段。以下是一些有效的预防措施&#xff1a; 可以通过域之盾软件来实现数据防丢失&#xff0c;具体的功能包括&#xff1a; https://www.yuzhidun.cn/https://www.yuzhidun.cn/ 1、备份数据 定期备份所有重要数据&#xff0…

unittest指南——不拼花哨,只拼实用

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

代码随想录算法训练营第五十三天|1143.最长公共子序列 1035.不相交的线 53. 最大子序和

文档讲解&#xff1a;代码随想录 视频讲解&#xff1a;代码随想录B站账号 状态&#xff1a;看了视频题解和文章解析后做出来了 1143.最长公共子序列 class Solution:def longestCommonSubsequence(self, text1: str, text2: str) -> int:dp [[0] * (len(text2) 1) for _ i…

基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码

基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于法医调查优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

windows11上安装WSL

Windows电脑上要配置linux&#xff08;这里指ubuntu&#xff09;开发环境&#xff0c;主要有三种方式&#xff1a; 1&#xff09;在windows上装个虚拟机&#xff08;比如vmware&#xff09;。缺点是vmware加载ubuntu后系统会变慢很多&#xff0c;而且需要通过samba来实现window…

计算机组成原理。3-408

1.动态存储和静态存储 2.双端口RAM 注意&#xff1a;cpu通过地址线和数据线读写数据时&#xff0c;不能同时写&#xff0c;但可以同时读&#xff0c;也不能一边读一边写。 3.多体并行存储器 分为高位存储和低位存储 小结 4.磁盘存储器的组成 5.磁盘的性能指标 磁盘读写寻道…

Vue中Slot的使用指南

目录 前言 什么是slot&#xff1f; 单个slot的使用 具名slot的使用 作用域插槽 总结 前言 在Vue中&#xff0c;slot是一种非常强大和灵活的功能&#xff0c;它允许你在组件模板中预留出一个或多个"插槽"&#xff0c;然后在使用这个组件的时候动态地填充内容。这…

TSINGSEE青犀智能分析网关道路积水识别AI算法方案

在各处的街道、路口等区域&#xff0c;及时发现道路积水问题&#xff0c;可以大大减少城市管理部门压力&#xff0c;及时处理&#xff0c;减少交通事故与人员摔倒事故。通过道路积水AI算法&#xff0c;能有效提高城市管理部门效率&#xff0c;优化城市管理方式。 那么&#xff…

【Web】PhpBypassTrick相关例题wp

目录 ①[NSSCTF 2022 Spring Recruit]babyphp ②[鹤城杯 2021]Middle magic ③[WUSTCTF 2020]朴实无华 ④[SWPUCTF 2022 新生赛]funny_php 明天中期考&#xff0c;先整理些小知识点冷静一下 ①[NSSCTF 2022 Spring Recruit]babyphp payload: a[]1&b1[]1&b2[]2&…

NLP的使用

参考&#xff1a; Apache openNLP 简介 - 链滴 (ld246.com) opennlp 模型下载地址&#xff1a;Index of /apache/opennlp/models/ud-models-1.0/ (tencent.com) OpenNLP是一个流行的开源自然语言处理工具包&#xff0c;它提供了一系列的NLP模型和算法。然而&#xff0c;Open…

【模拟开关CH440R】2022-1-20

资料模拟开关CH440芯片手册 - 百度文库 ch440R回来了&#xff0c;导通usb设备没问题&#xff0c;降压不影响。但是我发现个严重的问题&#xff0c;我的电路是直接通过4067控制ch440r接地&#xff0c;低电平&#xff0c;使能三个线路连一起的&#xff0c;邮箱的图您看看&#xf…

N-134基于java实现捕鱼达人游戏

开发工具eclipse,jdk1.8 文档截图&#xff1a; package com.qd.fish;import java.awt.Graphics; import java.io.File; import java.util.ArrayList; import java.util.List;import javax.imageio.ImageIO;public class Fishes {//定义一个集合来管理鱼List<Fish> fish…

五种多目标优化算法(NSDBO、NSGA3、MOGWO、NSWOA、MOPSO)求解微电网多目标优化调度(MATLAB代码)

一、多目标优化算法简介 &#xff08;1&#xff09;非支配排序的蜣螂优化算法NSDBO 多目标应用&#xff1a;基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度&#xff08;MATLAB&#xff09;-CSDN博客 &#xff08;2&#xff09;NSGA3 NSGA-III求解微电网多目标…

应用场景丨社区燃气管网监测系统建设

燃气作为现代社会的重要能源&#xff0c;燃气被广泛应用于居民生活、工业生产、商业服务等领域。然而&#xff0c;燃气泄漏事故时有发生&#xff0c;不仅给人们的生命财产安全带来严重威胁&#xff0c;也给燃气行业的发展带来不良影响。因此&#xff0c;对于燃气管道的监测和管…

给虚拟机配置静态id地址

1.令人头大的原因 当连接虚拟机的时候 地址不一会就改变&#xff0c;每次都要重新输入 2.配置虚拟机静态id地址 打开命令窗口执行 : vim /etc/sysconfig/network-scripts/ifcfg-ens33 按下面操作修改 查看自己子网掩码 3.重启网络 命令行输入 systemctl restart netwo…