趋近智
K-均值聚类是一种被广泛使用的算法,用于将数据集划分为预设数量的不同且不重叠的子群或簇。它是一种迭代算法,旨在通过最小化每个数据点到其所属簇中心(或算术平均值)的平方距离之和来找出局部最优解。这种方法对于识别无标签数据中的潜在群组结构很有效,这是无监督学习中的一项常见任务。
K-均值算法通过一个直接的迭代过程,将每个数据点分配到 个簇中的一个。主要思想是不断调整簇的中心和点的分配,直到达到稳定的状态。
主要步骤如下:
K-均值算法的迭代优化过程如下所示:
K-均值算法迭代地将数据点分配给簇并更新簇中心,直到收敛。
K-均值算法试图最小化的目标函数是簇内平方和(WCSS),也称为惯性: 其中 是簇的数量, 是簇 中的点集, 是簇 的中心。
在Julia中,Clustering.jl 包提供了K-均值及其他聚类算法的高效实现。如果您尚未安装,可以使用Julia的包管理器添加它:
using Pkg
Pkg.add("Clustering")
Pkg.add("Plots") # 用于可视化
Pkg.add("Random") # 用于生成样本数据
我们来看一个基本例子。首先,我们将生成一些具有自然分组的合成二维数据。
using Clustering, Plots, Random
# 设置随机种子以复现结果
Random.seed!(1234)
# 生成包含三个不同群组的合成数据
# 群组 1
X1 = randn(2, 50) .* 0.5 .+ [2.0; 2.0]
# 群组 2
X2 = randn(2, 50) .* 0.5 .+ [4.0; 4.0]
# 群组 3
X3 = randn(2, 50) .* 0.5 .+ [3.0; 0.0]
# 将群组合并为单个数据集
# Clustering.jl 要求数据列为特征,行为观测值
X_combined = hcat(X1, X2, X3)
data_points = permutedims(X_combined) # 转置,使观测值为行
# 执行 K-均值聚类
# 我们指定 k=3,因为我们知道合成数据有三个群组
k = 3
result = kmeans(data_points', k; display=:iter) # data_points' 表示特征作为列
# 访问结果
assignments = result.assignments # 每个点的簇分配
centroids = result.centers # 簇中心的坐标 (特征为行)
total_cost = result.totalcost # 最终聚类的 WCSS
iterations = result.iterations # 执行的迭代次数
converged = result.converged # 指示算法是否收敛的布尔值
println("点数量: ", size(data_points, 1))
println("簇分配 (前 10 个): ", assignments[1:10])
println("簇中心:\n", permutedims(centroids)) # 显示簇中心,特征作为列
println("总 WCSS: ", total_cost)
println("迭代次数: ", iterations)
println("已收敛: ", converged)
在 kmeans 函数中,data_points' 意味着我们提供的数据以特征为列、观测值为行,这是某些Julia机器学习包的常见约定。display=:iter 选项会显示算法的进度。result 对象是一个 KmeansResult 结构体,包含有关聚类结果的详细信息。
K-均值算法的主要难点之一是您需要预先指定簇的数量 。在许多实际情况下,最优的 是未知的。有几种方法可以辅助做出此决定:
我们来使用合成数据计算不同 值的WCSS:
# data_points' 表示特征为列,观测值为行
data_for_kmeans = data_points' # 来自上一个例子
max_k = 10
wcss_values = Float64[]
for k_val in 1:max_k
r = kmeans(data_for_kmeans, k_val)
push!(wcss_values, r.totalcost)
end
# 下面的 Plotly 图表将此可视化。
# 您也可以使用 Plots.jl 快速绘图:
# plot(1:max_k, wcss_values, xlabel="簇的数量 (k)", ylabel="WCSS", marker=:o, legend=false)
WCSS 通常随 的增加而减小。“肘部”点(在此示例中约为 )表明了合适的簇数量,在该点之后,增加更多簇会带来递减的回报。
轮廓分析:此方法测量一个数据点与其自身簇的相似程度,并与与其他簇的相似程度进行比较。轮廓得分的范围是 -1 到 1。较高的值表示簇之间分离良好。我们将在本章稍后更细致地介绍像轮廓得分这样的评价指标。
领域知识:通常,关于数据或问题背景的先验知识可以表明一个自然的簇数量。
Clustering.jl 的 kmeans 函数默认使用“k-means++”初始化方法。这种方法通常比纯随机初始化带来更好、更一致的结果。您可以控制初始化的部分(例如,init=:kmcen 用于k-均值中心选择或提供您自己的初始簇中心)。Clustering.jl 的默认设置(k-means++)通常使这变得不那么必要,但如果需要,可以使用 nruns 参数。对簇进行可视化可以提供重要的了解,特别是对于二维或三维数据。我们来使用 Plots.jl 绘制之前示例中的 3 簇结果。
# 使用 k=3 示例的结果:
# data_points (观测值为行,特征为列)
# assignments (每个点的簇 ID)
# centroids (特征为行,簇为列)
# 准备绘图数据
x_coords = data_points[:, 1]
y_coords = data_points[:, 2]
# 簇中心 (如果特征是行,绘图时需要转置)
# result.centers 是特征为行,簇为列。
# 因此,centroids_plot 是簇为行,特征(坐标)为列。
centroids_plot = permutedims(result.centers)
# 创建散点图
p = scatter(x_coords, y_coords, group=assignments,
xlabel="特征 1", ylabel="特征 2",
title="K-均值聚类 (k=3)",
legend=:outertopright, palette=:viridis) # :viridis 只是一个选项
# 将簇中心添加到图中
scatter!(p, centroids_plot[:, 1], centroids_plot[:, 2],
markershape=:xcross, markersize=8, markercolor=:red,
label="簇中心", seriesalpha=1)
# 在典型 Julia 环境中显示图表:
# display(p)
# 如果使用自动显示图表的笔记本或环境,这可能不需要。
二维数据上的 K-均值聚类示例。点按其所属簇着色,簇中心用红色叉号标记。
Plots.jl库与 GR 或 PlotlyJS 等后端配合使用可以生成此类可视化。
K-均值受欢迎是有充分理由的,但需要了解它的特点:
优点:
局限性:
尽管存在局限性,但 K-均值因其简单性和效率,通常是聚类任务的一个良好起点。了解其行为和假设对于有效地应用它并解读其结果是必要的。本章稍后,我们将研究 DBSCAN,这是一种基于密度的聚类算法,它能应对其中一些局限,例如找出任意形状的簇且无需预先指定 。
这部分内容有帮助吗?
Clustering.jl 包的官方文档,提供了其 K-Means 实现、API 以及在 Julia 中进行聚类的各种选项的详细信息。© 2026 ApX Machine Learning用心打造