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

ops/2024/11/18 3:36:04/

解锁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} 次迭代后收敛。")breakcentroids = new_centroidsreturn 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中实现该算法,并将其应用于真实数据的聚类分析中。


http://www.ppmy.cn/ops/134211.html

相关文章

初识Linux · 信号产生

目录 前言&#xff1a; 预备知识 信号产生 前言&#xff1a; 前文已经将进程间通信介绍完了&#xff0c;介绍了相关的的通信方式。在本文介绍的是信号部分&#xff0c;那么一定有人会有问题是&#xff1a;信号和信号量之间的关系是什么呢&#xff1f;答案是&#xff0c;它们…

036集——查询CAD图元属性字段信息:窗体显示(CAD—C#二次开发入门)

提取CAD图元所有属性字段&#xff0c;通过窗体显示&#xff0c;效果如下&#xff1a;&#xff08;curve改为entity&#xff09; 代码如下&#xff1a; public void 属性查询() {List<Curve> ents Z.db.SelectEntities<Curve>();if (ents is null ||ents.Cou…

如何绕过Captcha并使用OCR技术抓取数据

背景/引言 在现代的网页数据抓取中&#xff0c;Captcha&#xff08;全自动区分计算机和人类的图灵测试&#xff09;作为一种防止爬虫和恶意访问的有效措施&#xff0c;广泛应用于各种网站。Captcha的主要目的是区分用户是人类还是程序&#xff0c;因此对于爬虫技术来说&#x…

入侵检测算法平台部署LiteAIServer视频智能分析平台行人入侵检测算法:科技守护安全的新篇章

在现代化城市快速发展的背景下&#xff0c;安全防范已成为城市管理与社会生活中不可或缺的一环。随着人工智能、大数据、物联网等技术的飞速发展&#xff0c;智能化安防系统正逐步改变着传统的安全防护模式&#xff0c;特别是在行人入侵检测领域&#xff0c;视频智能分析平台Li…

大语言模型在序列推荐中的应用

一、简介 序列推荐技术通过分析用户的过往交互历史&#xff0c;能够有效挖掘出用户可能感兴趣的项目&#xff0c;对于提升各类应用的服务质量具有重要作用。近期&#xff0c;大语言模型&#xff08;LLMs&#xff09;的发展在应对复杂的推荐问题上展现出了显著的优势。不过&…

多智能体系统实现无直接通信协同

摘要&#xff1a;本文提出创新多智能体强化学习框架&#xff0c;通过对比学习构建全局共识&#xff0c;使智能体在没有直接通信的情况下实现协作行为。 近期&#xff0c;北京航空航天大学研究团队著作成果"Hierarchical Consensus-Based Multi-Agent Reinforcement Learn…

深度学习中的Pixel Shuffle和Pixel Unshuffle:图像超分辨率的秘密武器

在深度学习的计算机视觉任务中&#xff0c;提升图像分辨率和压缩特征图是重要需求。Pixel Shuffle和Pixel Unshuffle是在超分辨率、图像生成等任务中常用的操作&#xff0c;能够通过转换空间维度和通道维度来优化图像特征表示。本篇文章将深入介绍这两种操作的原理&#xff0c;…

Win10/11 安装使用 Neo4j Community Edition

如果你下载的是 Neo4j Community Edition 的压缩包&#xff0c;意味着你需要手动解压并配置 Neo4j。以下是详细的使用步骤&#xff1a; 0. 下载压缩包 访问Neo4j官网&#xff0c;找到 Community Edition 版本并选择 4.x 或者 5.x 下载&#xff1a;https://neo4j.com/deployme…