【人工智能】从零开始实现K-Means聚类:Python手动实现与算法原理详解

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界

K-Means是一种常用的无监督学习算法,广泛应用于数据聚类分析。本文将详细讲解K-Means的数学原理,包括目标函数和算法的迭代过程,阐述算法如何通过迭代优化簇的质心位置达到分类目的。同时,文章将使用Python从零实现一个完整的K-Means聚类算法,包括手动初始化、距离计算、簇的更新等步骤。通过详细的代码和中文注释,本文帮助读者深刻理解K-Means算法的本质和实现过程,最终展示如何使用该算法进行数据聚类和分析。


目录

  1. 引言
  2. K-Means算法原理
    • 2.1 算法概述
    • 2.2 目标函数定义
    • 2.3 算法的迭代过程
  3. Python手动实现K-Means算法
    • 3.1 数据准备
    • 3.2 初始化质心
    • 3.3 分配样本到最近的质心
    • 3.4 更新质心位置
    • 3.5 完整K-Means算法的实现
  4. 应用案例:使用K-Means进行数据聚类
  5. 结论

1. 引言

K-Means是一种无监督的聚类算法,其目的在于将数据分成K个簇,使得簇内样本间的距离尽可能小,而簇间距离尽可能大。尽管许多库中已经实现了K-Means算法,但手动实现算法有助于我们理解其迭代优化的过程。本文将从K-Means的数学原理出发,逐步实现K-Means聚类算法,并应用于实际数据的聚类分析中。


2. K-Means算法原理

2.1 算法概述

K-Means算法的核心是通过不断迭代调整簇的质心位置来最小化簇内的样本距离。算法的主要步骤如下:

  1. 随机选择K个点作为初始质心。
  2. 将每个样本分配到距离最近的质心,从而形成K个簇。
  3. 重新计算每个簇的质心(簇内样本的平均位置)。
  4. 重复步骤2和3,直到质心位置不再发生变化(或变化小于设定的阈值)。
2.2 目标函数定义

K-Means的目标是最小化所有样本到其所属簇质心的欧氏距离之和。给定数据集 X = { x 1 , x 2 , … , x n } \mathbf{X} = \{x_1, x_2, \dots, x_n\} X={x1,x2,,xn},其中每个样本点 x i ∈ R d x_i \in \mathbb{R}^d xiRd,算法通过选择K个质心 C = { c 1 , c 2 , … , c K } \mathbf{C} = \{c_1, c_2, \dots, c_K\} C={c1,c2,,cK} 来最小化以下目标函数:

J ( X , C ) = ∑ i = 1 n ∑ j = 1 K 1 ( x i ∈ C j ) ∥ x i − c j ∥ 2 J(\mathbf{X}, \mathbf{C}) = \sum_{i=1}^{n} \sum_{j=1}^{K} \mathbf{1}(x_i \in C_j) \|x_i - c_j\|^2 J(X,C)=i=1nj=1K1(xiCj)xicj2

其中:

  • ∥ x i − c j ∥ 2 \|x_i - c_j\|^2 xicj2 表示样本 x i x_i xi 到质心 c j c_j cj 的欧氏距离。
  • 1 ( x i ∈ C j ) \mathbf{1}(x_i \in C_j) 1(xiCj) 是指示函数,表示 x i x_i xi 是否属于第 j j j 个簇。
2.3 算法的迭代过程

K-Means通过以下两个步骤交替进行来优化目标函数:

  1. 簇分配步骤:将每个样本点分配到最近的质心。

    对于每个样本点 x i x_i xi,找到与其距离最近的质心 c j c_j cj,并将 x i x_i xi 分配给簇 C j C_j Cj。计算距离通常使用欧氏距离:

    ∥ x i − c j ∥ = ∑ k = 1 d ( x i k − c j k ) 2 \|x_i - c_j\| = \sqrt{\sum_{k=1}^{d} (x_{ik} - c_{jk})^2} xicj=k=1d(xikcjk)2

  2. 质心更新步骤:重新计算每个簇的质心,即簇内所有样本的平均位置:

    c j = 1 ∣ C j ∣ ∑ x i ∈ C j x i c_j = \frac{1}{|C_j|} \sum_{x_i \in C_j} x_i cj=Cj1xiCjxi

迭代结束条件通常为质心位置不再变化,或达到设定的最大迭代次数。


3. Python手动实现K-Means算法

3.1 数据准备

我们先创建一个数据集以便后续测试K-Means算法。为简化演示,我们使用二维数据。

import numpy as np
import matplotlib.pyplot as plt

# 生成样本数据
np.random.seed(42)
num_samples_per_cluster = 50
centers = [[2, 2], [8, 3], [3, 6]]
cluster_std = [0.8, 0.5, 1.0]

# 创建三个不同簇的数据点
X = []
for i, center in enumerate(centers):
    X.append(np.random.normal(loc=center, scale=cluster_std[i], size=(num_samples_per_cluster, 2)))
X = np.vstack(X)
3.2 初始化质心

为了实现K-Means,首先需要随机初始化K个质心。这些质心可以从数据集中随机选择。

def initialize_centroids(X, K):
    """从数据集中随机选择K个点作为初始质心"""
    indices = np.random.choice(X.shape[0], K, replace=False)
    centroids = X[indices]
    return centroids

# 测试初始化
K = 3  # 假设分为3个簇
initial_centroids = initialize_centroids(X, K)
print("初始质心:\n", initial_centroids)
3.3 分配样本到最近的质心

接下来,我们实现样本分配函数,即计算每个样本到所有质心的距离,并分配给最近的质心。

def assign_clusters(X, centroids):
    """将每个样本分配到最近的质心"""
    clusters = []
    for x in X:
        distances = [np.linalg.norm(x - centroid) for centroid in centroids]
        closest_index = np.argmin(distances)
        clusters.append(closest_index)
    return np.array(clusters)

# 测试分配函数
clusters = assign_clusters(X, initial_centroids)
print("分配的簇索引:\n", clusters)
3.4 更新质心位置

根据分配好的簇,我们可以计算每个簇内所有样本的均值,更新质心位置。

def update_centroids(X, clusters, K):
    """更新质心的位置,计算每个簇的均值"""
    new_centroids = []
    for k in range(K):
        cluster_points = X[clusters == k]
        new_centroid = cluster_points.mean(axis=0)
        new_centroids.append(new_centroid)
    return np.array(new_centroids)

# 测试更新质心
updated_centroids = update_centroids(X, clusters, K)
print("更新后的质心:\n", updated_centroids)
3.5 完整K-Means算法的实现

我们可以将上述步骤合并到一个完整的K-Means算法中,实现迭代优化,直到质心不再发生明显变化。

def kmeans(X, K, max_iters=100, tol=1e-4):
    """K-Means算法实现"""
    # 随机初始化质心
    centroids = initialize_centroids(X, K)
    
    for i in range(max_iters):
        # 分配样本到最近的质心
        clusters = assign_clusters(X, centroids)
        
        # 更新质心
        new_centroids = update_centroids(X, clusters, K)
        
        # 计算质心移动的距离
        centroid_shifts = np.linalg.norm(new_centroids - centroids, axis=1)
        
        # 检查是否满足停止条件
        if np.all(centroid_shifts < tol):
            print(f"算法在第 {i} 次迭代后收敛。")
            break
        
        centroids = new_centroids
    
    return centroids, clusters

# 运行K-Means算法
final_centroids, final_clusters = kmeans(X, K)
print("最终质心:\n", final_centroids)

4. 应用案例:使用K-Means进行数据聚类

使用我们实现的K-Means算法对数据进行聚类,并可视化结果。

# 绘制聚类结果
def plot_clusters(X, clusters, centroids):
    plt.scatter(X[:, 0], X[:, 1], c=clusters, cmap='viridis', marker

='o', s=50)
    plt.scatter(centroids[:, 0], centroids[:, 1], c='red', marker='x', s=200, label='Centroids')
    plt.xlabel("Feature 1")
    plt.ylabel("Feature 2")
    plt.legend()
    plt.title("K-Means Clustering")
    plt.show()

# 绘制结果
plot_clusters(X, final_clusters, final_centroids)

通过此可视化,我们可以清楚地看到每个簇的分布情况,以及质心在数据分布中的位置。


5. 结论

本文从数学原理和代码实现两个方面详细介绍了K-Means聚类算法。通过手动实现K-Means,我们可以更清楚地理解其聚类过程:从随机初始化质心到迭代更新,以及目标函数的优化。K-Means是机器学习和数据分析中非常重要的无监督学习算法之一,理解其基本原理和实现过程能够帮助我们在数据聚类和探索中更好地应用它。

通过这篇文章,读者不仅能够掌握K-Means的理论,还可以在Python中实现该算法,并将其应用于真实数据的聚类分析中。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

<项目代码>YOLOv8 手机识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

算法定制LiteAIServer摄像机实时接入分析平台烟火识别检测算法

在公共安全领域&#xff0c;火灾的及时发现与处理是保障人民群众生命财产安全的重要手段。传统的烟火检测手段受限于人工巡查的局限&#xff0c;难以做到全天候、无遗漏的监控。然而&#xff0c;随着人工智能技术的飞速发展&#xff0c;LiteAIServer摄像机实时接入分析平台烟火…

JMeter与大模型融合应用之JMeter日志分析服务化实战应用

JMeter与大模型融合应用之JMeter日志分析服务化 引言 在当今的互联网时代,网站和应用程序的性能直接影响到用户的体验和业务的成功。为了保证系统的稳定性和高效性,性能测试成为了软件开发过程中的一个重要环节。在这其中,Apache JMeter作为一款开源的性能测试工具,凭借其…

【Pikachu】任意文件上传实战

将过去和羁绊全部丢弃&#xff0c;不要吝惜那为了梦想流下的泪水。 1.不安全的文件上传漏洞概述 不安全的文件上传漏洞概述 文件上传功能在web应用系统很常见&#xff0c;比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后&#xff0c;后台会对上传的…

STM32 ADC --- 单通道采样

STM32 ADC — 单通道采样 文章目录 STM32 ADC --- 单通道采样cubeMX配置代码修改&#xff1a;应用 使用cubeMX生成HAL工程 需求&#xff1a;有多个通道需要进行ADC采样&#xff0c;实现每次采样只采样一个通道&#xff0c;且可以随时采样不同通道的功能。 cubeMX配置 这里我们…

influxDB 时序数据库安装 flux语法 restful接口 nodjsAPI

安装 Install InfluxDB | InfluxDB OSS v2 Documentation Debian和Ubuntu用户可以用apt-get包管理来安装最新版本的InfluxDB。 对于Ubuntu用户&#xff0c;可以用下面的命令添加InfluxDB的仓库&#xff0c;添加之后即可apt-get 安装influxdb2 wget -q https://repos.influx…

【轻量化】YOLOv10 更换骨干网络之 MobileNetv4 | 模块化加法!非 timm 包!

之前咱们在这个文章中讲了timm包的加法,不少同学反馈要模块化的加法,那么这篇就讲解下模块化的加法,值得注意的是,这样改加载不了mobilebnetv4官方开源的权重了~ 论文地址:https://arxiv.org/pdf/2404.10518 代码地址:https://github.com/tensorflow/models/blob/master…

电气自动控制电路图图例

单相照明双路互备自投供电电路 双路三相电源自投电路 茶炉水加热自动控制电路 简单的温度控制器电路 简易晶闸管温度自动控制电路 用双向晶闸管控制温度电路 XCT-101动圈式温度调节仪控温电路 电接点压力式温度表控温电路 TDA-8601型温度指示调节仪控温电路 XMT-DA数字…

D3 可以加载的数据格式有哪些?(12种)

D3.js 支持多种数据格式&#xff0c;这些格式涵盖了从简单的表格数据到复杂的地理数据。以下是一些常见的数据格式及其加载方法&#xff1a; D3.js 数据加载方法 d3.blob(input, init) 用途: 加载二进制数据&#xff0c;返回一个 Blob 对象。参数: input: 数据源 URL。init: …

Pinpoint(APM)进阶--Pinot指标采集(System Metric/Inspector)

接上文 Pinpoint使用Pinot进行指标数据存储&#xff0c;Pinot流摄入需要Kafka 本文详解Kafka和Pinot的安装部署&#xff0c;以及Pinpoint的指标采集 Pinot 简介 Apache Pinot是一个实时分布式OLAP数据存储&#xff0c;专为低延迟、高吞吐量分析而构建&#xff0c;非常适合面…

mmsegmentation: 安装 并使用自定义数据集进行训练 ·2

我用的是CHASE_DB1.py 数据集下载链接 https://staffnet.kingston.ac.uk/~ku15565/CHASE_DB1/assets/CHASEDB1.zip 这个用来转换mmseg所需要的格式 python tools/dataset_converters/chase_db1.py /path/to/CHASEDB1.zip其他数据集请看链接&#xff1a;https://mmsegmenta…

通义千问API调用测试 (colab-python,vue)

文章目录 代码&#xff08;来自官网&#xff09;colab中用python测试Qwen2.5在官网上查看并确定过期时间这里看到我的免费额度到25年5月在同一个页面&#xff0c;点击API示例 前端调用直接在前端调用的优缺点以vue为例&#xff08;代码是基于官网node.js的代码转换而来&#xf…

【c++笔试强训】(第九篇)

目录 链表相加&#xff08;⼆&#xff09;&#xff08;链表⾼精度加法&#xff09; 题目解析 讲解算法原理 编写代码 ⼤数乘法&#xff08;⾼精度乘法&#xff09; 题目解析 讲解算法原理 辨析代码 链表相加&#xff08;⼆&#xff09;&#xff08;链表⾼精度加法&#…

C#高级:使用Invoke关键字通过 Type 类型调用指定的方法

demo如下&#xff1a; using System.Reflection; using System;public class Program {public class Calculator{public int Add(int a, int b){return a b;}}public class Student{public string Name { get; set; }}public class Example{// 泛型方法public string Generi…

B-树特点以及插入、删除数据过程

B树&#xff08;B-Tree&#xff09;是一种自平衡的多路查找树&#xff0c;它广泛应用于数据库索引和文件系统中&#xff0c;尤其适用于外部存储设备&#xff08;如磁盘&#xff09;。B树的设计使得它能够高效地存储大量数据并支持高效的插入、删除和查询操作。以下是B树的主要特…

自定义反序列化过程

需求&#xff1a;student对象中name属性&#xff0c;序列化时将该属性映射为stuname&#xff0c;反序列化时将 Json中的NAME键值对映射到name属性中 AllArgsConstructorNoArgsConstructorGetterSetterstatic class Student {JsonProperty("stuname")private List<…

解读 ConcurrentHashMap 源码:探索高并发场景下的卓越性能

ConcurrentHashMap 了&#xff0c;作为线程安全的 HashMap &#xff0c;它的使用频率也是很高。那么它的存储结构和实现原理是怎么样的呢&#xff1f;HashMap 源码&#xff1a;揭开哈希表背后的秘密 1、ConcurrentHashMap 1.7 1. 存储结构 Java 7 中 ConcurrentHashMap 的存储…

为什么配置TIM11作为系统时基的时候会出现__NVIC_PRIO_BITS

回想起当初学freertos的时候&#xff0c;某个中断优先级以下的任务是不能被freertos管理的&#xff08;好像是全是抢占优先级&#xff0c;0子优先级的设置&#xff09;。当初还不是非常了解。只知道管理不了 HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) {RCC_ClkI…

数字IC实践项目(10)—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证(付费项目)

数字IC实践项目&#xff08;10&#xff09;—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证&#xff08;付费项目&#xff09; 前言项目框图1&#xff09;DDR4 Verification IP2&#xff09;DDR4 JEDEC Model & Tb 项目文件1&#xff09;DDR4 Veri…

python解析网页上的json数据落地到EXCEL

安装必要的库 import requests import pandas as pd import os import sys import io import urllib3 import json测试数据 网页上的数据结构如下 {"success": true,"code": "CIFM_0000","encode": null,"message": &quo…