趋近智
K-Means聚类是一种特定且广泛应用于数据分区的技术,属于无监督学习的范畴。K-Means的目标直接明了:根据相似性将数据点分成预设数量()的不同、不重叠的群组。同一群组内的数据点应彼此相似,而不同群组中的点则应不相似。
K-Means是一种迭代算法,旨在最小化数据点与其所属群组中心之间的距离。群组的“中心”被称为质心,通常计算为该群组内所有数据点的平均值。
该算法通过以下主要步骤进行:
该算法的目标是最小化簇内平方和 (WCSS),通常称为惯性。这是每个数据点与其所属群组质心之间平方距离的总和:
其中是群组数量,是群组中的点集,是群组的质心,是欧几里得距离的平方。
Scikit-learn通过sklearn.cluster.KMeans类提供了K-Means的便捷实现。我们来看一个实际例子。
首先,我们需要一些数据。我们将使用scikit-learn的make_blobs函数生成具有不同群组的合成数据,这对于说明K-Means如何工作很有帮助。
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# 生成具有3个中心的人工数据
X, y_true = make_blobs(n_samples=300, centers=3, cluster_std=0.80, random_state=42)
# 对数据进行标准化(对K-Means很重要)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 实例化KMeans
# 我们指定n_clusters (k) = 3,因为我们知道此示例的真实结构
# n_init=10 用不同的质心种子运行算法10次
# 最终结果将是惯性方面最好的输出
kmeans = KMeans(n_clusters=3, init='k-means++', n_init=10, random_state=42)
# 将模型拟合到标准化数据
kmeans.fit(X_scaled)
# 获取群组分配和质心
labels = kmeans.labels_
centroids = kmeans.cluster_centers_
# --- 使用Plotly进行可视化 ---
# 创建数据点的散点图,按预测的群组标签着色
fig = go.Figure()
# 添加数据点
fig.add_trace(go.Scatter(
x=X_scaled[:, 0], y=X_scaled[:, 1],
mode='markers',
marker=dict(
color=labels, # 根据群组标签分配颜色
colorscale=['#1f77b4', '#ff7f0e', '#2ca02c'], # 示例颜色
opacity=0.8,
line=dict(width=0.5, color='#495057')
),
name='数据点'
))
# 添加质心
fig.add_trace(go.Scatter(
x=centroids[:, 0], y=centroids[:, 1],
mode='markers',
marker=dict(
color='#d62728', # 质心的红色
size=12,
symbol='x',
line=dict(width=2, color='#FFFFFF') # 白色边框以增加可见性
),
name='质心'
))
# 更新布局以获得更好的外观
fig.update_layout(
title='K-Means聚类结果 (k=3)',
xaxis_title='特征1(标准化)',
yaxis_title='特征2(标准化)',
showlegend=True,
plot_bgcolor='#e9ecef', # 浅灰色背景
width=700,
height=500
)
# 要显示图表(例如在Jupyter环境中):
# fig.show()
# 或保存为HTML:
# fig.write_html("kmeans_clusters.html")
# Plotly JSON对象(用于嵌入Web环境)
plotly_json = fig.to_json()
散点图显示了根据K-Means分配的群组进行着色的数据点。红色的“x”标记表示群组质心的最终位置。
在代码中:
n_clusters=3:我们告诉K-Means寻找3个群组。init='k-means++':使用k-means++初始化方法来获取更优的质心起始点。n_init=10:用不同的随机初始化运行K-Means算法10次,并返回基于WCSS(惯性)的最佳结果。这有助于减少因初始化不佳而陷入次优解的问题。random_state=42:确保结果的可复现性。.fit(X_scaled):在标准化数据上训练K-Means模型。.labels_:一个数组,包含分配给每个数据点的群组索引(在此示例中为0、1或2)。.cluster_centers_:一个NumPy数组,包含最终质心的坐标。K-Means的一个重要挑战是,您通常事先不知道最优群组数量()。肘部法则是一种常用的启发式方法,用于选择一个合适的值。
其思路是,对一系列不同的值(例如,从1到10)运行K-Means,并计算每次运行的WCSS(惯性)。然后,我们将WCSS与进行绘图。随着的增加,WCSS通常会下降,因为点会更接近较小群组的质心。然而,在某个点之后,下降的速度通常会明显减缓,在图表中形成一个“肘部”形状。肘部点的值通常被认为是群组数量的良好指引。
以下是实现肘部法则的方法:
import plotly.graph_objects as go
# 计算不同k值下的WCSS(惯性)
wcss = []
k_values = range(1, 11) # 测试k从1到10
for k in k_values:
kmeans_elbow = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42)
kmeans_elbow.fit(X_scaled)
wcss.append(kmeans_elbow.inertia_) # inertia_ 属性存储WCSS
# --- 使用Plotly进行可视化 ---
fig_elbow = go.Figure()
fig_elbow.add_trace(go.Scatter(
x=list(k_values),
y=wcss,
mode='lines+markers',
marker=dict(color='#1c7ed6', size=8),
line=dict(color='#1c7ed6', width=2)
))
# 突出显示潜在的肘部点(例如,本例中k=3)
elbow_k = 3
fig_elbow.add_vline(x=elbow_k, line_width=2, line_dash="dash", line_color="#fa5252",
annotation_text=f"潜在肘部点 (k={elbow_k})", annotation_position="top right")
fig_elbow.update_layout(
title='确定最优k值的肘部法则',
xaxis_title='群组数量 (k)',
yaxis_title='簇内平方和 (WCSS)',
plot_bgcolor='#e9ecef',
width=700,
height=400
)
# fig_elbow.show()
plotly_elbow_json = fig_elbow.to_json()
图表显示了WCSS与群组数量(k)的关系。“肘部”通常表示在最小化WCSS和保持群组数量适中之间的一种合理权衡。在这个合成示例中,肘部在k=3处清晰可见,与我们生成的真实群组数量相符。
“找到确切的肘部点有时可能是主观的,特别是在曲线可能更平滑的数据中。它作为一种指导,而非明确的规则。其他技术,如轮廓系数,提供了评估群组质量和选择值的替代方法。”
K-Means依赖距离计算(通常是欧几里得距离)将点分配到群组并更新质心。如果特征具有不同的尺度(例如,一个特征范围从0到1,另一个从1,000到100,000),那么范围较大的特征将不成比例地影响距离计算,进而影响聚类结果。
因此,在应用K-Means之前,对数值特征进行尺度调整或归一化是标准做法。常用的方法包括StandardScaler(将特征标准化为零均值和单位方差,如代码示例所示)或MinMaxScaler(将特征缩放到固定范围,通常是[0, 1])。这确保所有特征对距离计算的贡献更均衡。请记住在训练数据上拟合缩放器,并在聚类之前用它转换训练数据和任何新数据。
尽管强大而高效,K-Means在某些假设下运作,这可能限制其在某些情况下的有效性:
n_init参数)有助于找到更稳定的解。理解这些局限对于解释结果以及判断K-Means是否适合您的特定数据集和问题是很重要的。对于具有非球形群组或密度不一的数据集,其他算法,例如DBSCAN(接下来讨论),可能更合适。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造