K-Means聚类算法原理与实战优化指南
1. 项目概述K-Means聚类作为机器学习领域最经典的算法之一其简洁性和高效性使其成为数据科学入门必学的算法。但很多教程要么过于理论化要么代码实现过于简化导致学习者难以真正掌握其精髓。这个项目将从数学原理推导开始逐步实现完整的K-Means算法最后通过真实数据集演示完整应用流程。我在金融风控领域使用K-Means进行客户分群时发现很多现成工具库的默认参数在实际业务场景中效果并不理想。通过这个项目我想分享如何根据具体数据特性调整算法参数以及如何避免常见的聚类陷阱。2. 核心原理拆解2.1 算法数学基础K-Means的核心思想是通过迭代寻找K个簇的中心点使得所有数据点到其所属簇中心的平方距离之和最小。这个优化目标可以用以下公式表示J Σ(i1 to K) Σ(x∈C_i) ||x - μ_i||²其中C_i 表示第i个簇μ_i 表示第i个簇的中心点||x - μ_i||² 表示数据点x到中心点的欧式距离平方这个目标函数被称为畸变函数(Distortion Function)算法的每次迭代都在尝试减小这个函数值。2.2 关键参数解析K值选择肘部法则(Elbow Method)绘制不同K值对应的畸变值曲线选择拐点处的K值轮廓系数(Silhouette Coefficient)综合考虑簇内紧密度和簇间分离度实际业务需求比如客户分级可能需要特定的层级数量距离度量欧式距离最常用适用于连续型数值特征余弦相似度适合文本等稀疏高维数据马氏距离考虑特征间相关性的度量方式初始化方法随机初始化简单但可能收敛到局部最优K-Means通过概率分布优化初始中心点选择基于先验知识的初始化利用领域知识指定初始中心3. 完整代码实现3.1 基础版本实现我们先实现一个最基础的K-Means算法包含以下核心函数import numpy as np from sklearn.metrics import pairwise_distances class KMeansBasic: def __init__(self, n_clusters8, max_iter300, tol1e-4): self.n_clusters n_clusters self.max_iter max_iter self.tol tol self.centroids None def fit(self, X): # 随机初始化中心点 n_samples X.shape[0] random_indices np.random.choice(n_samples, self.n_clusters, replaceFalse) self.centroids X[random_indices] for _ in range(self.max_iter): # 分配样本到最近的中心 distances pairwise_distances(X, self.centroids) labels np.argmin(distances, axis1) # 计算新中心 new_centroids np.array([ X[labels i].mean(axis0) for i in range(self.n_clusters) ]) # 检查收敛 if np.linalg.norm(new_centroids - self.centroids) self.tol: break self.centroids new_centroids return self3.2 优化版本实现在基础版本上我们添加几个重要优化K-Means初始化def _kmeans_plusplus_init(self, X): n_samples X.shape[0] centroids [X[np.random.randint(n_samples)]] for _ in range(1, self.n_clusters): distances pairwise_distances(X, np.array(centroids)) min_distances np.min(distances, axis1) prob min_distances / min_distances.sum() next_centroid X[np.random.choice(n_samples, pprob)] centroids.append(next_centroid) return np.array(centroids)空簇处理# 在计算新中心时添加空簇处理 for i in range(self.n_clusters): if np.sum(labels i) 0: # 空簇处理 self.centroids[i] X[np.random.choice(n_samples)] else: new_centroids[i] X[labels i].mean(axis0)并行计算优化from joblib import Parallel, delayed def _update_centroid(X, labels, i): cluster_points X[labels i] if len(cluster_points) 0: return None return cluster_points.mean(axis0) # 在fit方法中使用并行计算 new_centroids Parallel(n_jobs-1)( delayed(_update_centroid)(X, labels, i) for i in range(self.n_clusters) )4. 实战应用案例4.1 客户细分案例我们使用一个真实的零售客户数据集来演示K-Means的应用import pandas as pd from sklearn.preprocessing import StandardScaler # 加载数据 data pd.read_csv(customer_data.csv) features [annual_income, purchase_frequency, avg_order_value] # 数据预处理 scaler StandardScaler() X scaler.fit_transform(data[features]) # 确定最佳K值 from sklearn.metrics import silhouette_score silhouette_scores [] for k in range(2, 11): kmeans KMeans(n_clustersk, random_state42).fit(X) score silhouette_score(X, kmeans.labels_) silhouette_scores.append(score) # 可视化选择最佳K值 import matplotlib.pyplot as plt plt.plot(range(2, 11), silhouette_scores) plt.xlabel(Number of clusters) plt.ylabel(Silhouette Score) plt.show()4.2 图像压缩案例K-Means也可以用于图像颜色压缩from sklearn.cluster import KMeans import matplotlib.image as mpimg # 加载图像 img mpimg.imread(test_image.jpg) h, w, d img.shape image_array img.reshape(h*w, d) # 使用K-Means进行颜色聚类 kmeans KMeans(n_clusters16, random_state42).fit(image_array) compressed_colors kmeans.cluster_centers_[kmeans.labels_] compressed_image compressed_colors.reshape(h, w, d) # 显示结果 fig, (ax1, ax2) plt.subplots(1, 2) ax1.imshow(img) ax1.set_title(Original Image) ax2.imshow(compressed_image) ax2.set_title(Compressed Image (16 colors)) plt.show()5. 高级技巧与优化5.1 处理不同尺度特征当特征尺度差异较大时需要进行适当的预处理标准化(Standardization)from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_scaled scaler.fit_transform(X)归一化(Normalization)from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler() X_normalized scaler.fit_transform(X)鲁棒缩放(Robust Scaling)from sklearn.preprocessing import RobustScaler scaler RobustScaler() X_robust scaler.fit_transform(X)5.2 类别型特征处理对于混合了数值型和类别型特征的数据可以采用以下方法One-Hot编码后拼接from sklearn.preprocessing import OneHotEncoder # 数值特征 num_features [age, income] # 类别特征 cat_features [gender, education] # 分别处理 num_scaler StandardScaler() X_num num_scaler.fit_transform(data[num_features]) encoder OneHotEncoder(sparseFalse) X_cat encoder.fit_transform(data[cat_features]) # 合并特征 X_combined np.hstack([X_num, X_cat])使用Gower距离import gower # 计算Gower距离矩阵 distance_matrix gower.gower_matrix(data) # 使用K-Medoids算法处理任意距离度量 from sklearn_extra.cluster import KMedoids kmedoids KMedoids(n_clusters5, metricprecomputed).fit(distance_matrix)6. 常见问题与解决方案6.1 空簇问题问题现象在迭代过程中某个簇可能失去所有成员导致计算新中心点时出错。解决方案重新初始化空簇的中心点将离当前中心最远的点作为新中心从最大簇中分割出部分点给空簇# 在fit方法中添加空簇处理 for i in range(self.n_clusters): if np.sum(labels i) 0: # 方案1随机选择一个点作为新中心 self.centroids[i] X[np.random.choice(n_samples)] # 方案2选择离所有中心最远的点 # farthest np.argmax(np.min(pairwise_distances(X, self.centroids), axis1)) # self.centroids[i] X[farthest]6.2 收敛速度慢问题原因数据维度高初始中心点选择不佳数据分布不均匀优化方案使用PCA降维采用K-Means初始化设置合理的停止阈值(tol)# 使用PCA降维 from sklearn.decomposition import PCA pca PCA(n_components0.95) # 保留95%方差 X_reduced pca.fit_transform(X) # 结合K-Means初始化 kmeans KMeans( n_clusters5, initk-means, tol1e-6, max_iter500 )6.3 聚类结果不稳定问题现象每次运行得到的结果差异较大解决方案设置固定随机种子多次运行选择最佳结果增加n_init参数值# 设置随机种子保证可重复性 np.random.seed(42) # 多次运行选择最佳结果 best_score -1 best_labels None for _ in range(10): kmeans KMeans(n_clusters5).fit(X) score silhouette_score(X, kmeans.labels_) if score best_score: best_score score best_labels kmeans.labels_7. 评估与可视化7.1 常用评估指标轮廓系数(Silhouette Score)from sklearn.metrics import silhouette_score score silhouette_score(X, kmeans.labels_)Calinski-Harabasz指数from sklearn.metrics import calinski_harabasz_score score calinski_harabasz_score(X, kmeans.labels_)Davies-Bouldin指数from sklearn.metrics import davies_bouldin_score score davies_bouldin_score(X, kmeans.labels_)7.2 可视化方法二维散点图plt.scatter(X[:, 0], X[:, 1], ckmeans.labels_, cmapviridis) plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s300, cred, markerx) plt.title(K-Means Clustering Results) plt.show()平行坐标图(高维数据)from pandas.plotting import parallel_coordinates df pd.DataFrame(X, columns[feature1, feature2, feature3]) df[cluster] kmeans.labels_ plt.figure(figsize(12, 6)) parallel_coordinates(df, cluster, colormapviridis) plt.title(Parallel Coordinates Plot by Cluster) plt.show()雷达图from math import pi # 计算每个簇的特征均值 cluster_means df.groupby(cluster).mean() # 设置雷达图角度 categories list(cluster_means.columns) N len(categories) angles [n / float(N) * 2 * pi for n in range(N)] angles angles[:1] fig plt.figure(figsize(8, 8)) ax fig.add_subplot(111, polarTrue) for i, row in cluster_means.iterrows(): values row.values.flatten().tolist() values values[:1] ax.plot(angles, values, linewidth2, linestylesolid, labelfCluster {i}) ax.fill(angles, values, alpha0.1) plt.xticks(angles[:-1], categories) plt.title(Radar Chart of Cluster Characteristics) plt.legend(locupper right) plt.show()8. 工程实践建议8.1 大数据量处理当数据量很大时可以考虑以下优化方案Mini-Batch K-Meansfrom sklearn.cluster import MiniBatchKMeans mbk MiniBatchKMeans(n_clusters5, batch_size1000) mbk.fit(X_large)数据采样from sklearn.utils import resample # 对大数据集进行采样 X_sample resample(X_large, n_samples100000, random_state42) kmeans KMeans(n_clusters5).fit(X_sample)分布式计算from pyspark.ml.clustering import KMeans as SparkKMeans # 创建Spark KMeans实例 spark_kmeans SparkKMeans(k5, seed42) model spark_kmeans.fit(spark_df)8.2 生产环境部署在实际生产环境中部署K-Means模型时模型持久化import joblib # 保存模型 joblib.dump(kmeans, kmeans_model.pkl) # 加载模型 loaded_model joblib.load(kmeans_model.pkl)增量学习# 使用partial_fit进行增量学习 mbk.partial_fit(new_data)API封装from flask import Flask, request, jsonify app Flask(__name__) model joblib.load(kmeans_model.pkl) app.route(/predict, methods[POST]) def predict(): data request.json features preprocess(data) cluster model.predict([features])[0] return jsonify({cluster: int(cluster)}) if __name__ __main__: app.run(host0.0.0.0, port5000)9. 算法局限性与替代方案9.1 K-Means的局限性需要预先指定K值对异常值敏感假设簇是凸形且大小相似受初始中心点选择影响大9.2 替代算法层次聚类(Hierarchical Clustering)from sklearn.cluster import AgglomerativeClustering hc AgglomerativeClustering(n_clusters5) labels hc.fit_predict(X)DBSCAN(基于密度的聚类)from sklearn.cluster import DBSCAN dbscan DBSCAN(eps0.5, min_samples5) labels dbscan.fit_predict(X)高斯混合模型(GMM)from sklearn.mixture import GaussianMixture gmm GaussianMixture(n_components5) labels gmm.fit_predict(X)谱聚类(Spectral Clustering)from sklearn.cluster import SpectralClustering sc SpectralClustering(n_clusters5) labels sc.fit_predict(X)10. 扩展应用与前沿方向10.1 半监督学习结合少量标记数据改进聚类效果from sklearn.semi_supervised import LabelPropagation # 假设我们有少量标记数据 y_partial np.array([0, 1, -1, -1, -1]) # -1表示未标记 # 使用标签传播 label_prop LabelPropagation(kernelknn, n_neighbors5) label_prop.fit(X, y_partial) full_labels label_prop.transduction_10.2 深度聚类结合深度学习的聚类方法from sklearn.cluster import KMeans from tensorflow.keras.layers import Input, Dense from tensorflow.keras.models import Model # 构建自编码器 input_layer Input(shape(X.shape[1],)) encoded Dense(64, activationrelu)(input_layer) encoded Dense(32, activationrelu)(encoded) decoded Dense(64, activationrelu)(encoded) decoded Dense(X.shape[1], activationsigmoid)(decoded) autoencoder Model(input_layer, decoded) autoencoder.compile(optimizeradam, lossmse) autoencoder.fit(X, X, epochs50, batch_size256) # 获取低维表示 encoder Model(input_layer, encoded) X_lowdim encoder.predict(X) # 在低维空间进行聚类 kmeans KMeans(n_clusters5) labels kmeans.fit_predict(X_lowdim)10.3 时间序列聚类针对时间序列数据的特殊聚类方法from tslearn.clustering import TimeSeriesKMeans # 假设X_time_series是三维数组(样本数, 时间步长, 特征数) ts_kmeans TimeSeriesKMeans(n_clusters5, metricdtw) labels ts_kmeans.fit_predict(X_time_series)在实际项目中我发现K-Means虽然简单但要获得好的聚类效果需要深入理解数据特性并精心调整参数。特别是在处理高维数据时适当的降维预处理往往能显著提升聚类质量。另外聚类结果的解释性也非常重要需要结合业务知识进行分析验证。

相关新闻

TI CC2564MODAEM蓝牙评估板:从硬件解析到低功耗BLE应用实战

TI CC2564MODAEM蓝牙评估板:从硬件解析到低功耗BLE应用实战

1. 项目概述与核心价值如果你正在为你的嵌入式设备寻找一个稳定、成熟且功能全面的蓝牙连接方案,那么德州仪器(TI)的CC2564MODAEM评估板绝对值得你花时间深入研究。这不是一个简单的“即插即用”模块,而是一个完整的双模蓝牙&…

2026/10/17 14:43:29 阅读更多 →
OpenCSG开源数据平台:提升中文AI数据质量与标注效率

OpenCSG开源数据平台:提升中文AI数据质量与标注效率

1. 项目背景与行业痛点中文AI数据领域长期面临三大核心困境:数据质量参差不齐、标注标准不统一、高质量语料稀缺。这直接导致中文NLP模型训练效果受限,尤其在专业领域应用中表现明显弱于英文模型。OpenCSG开源数据贡献平台的诞生,正是瞄准了这…

2026/10/17 14:46:44 阅读更多 →
本地开发环境搭建指南:gh_mirrors/ope/open-source-practice贡献者必备技能

本地开发环境搭建指南:gh_mirrors/ope/open-source-practice贡献者必备技能

本地开发环境搭建指南:gh_mirrors/ope/open-source-practice贡献者必备技能 【免费下载链接】open-source-practice Repo for you to raise a Pull Request for practice 项目地址: https://gitcode.com/gh_mirrors/ope/open-source-practice GitHub 加速计划…

2026/10/17 7:11:28 阅读更多 →

最新新闻

HTTP/3与QUIC深度解析:从队头阻塞到部署实战

HTTP/3与QUIC深度解析:从队头阻塞到部署实战

浏览器原理这个系列写到现在,HTTP/3是我最想写又最不敢写的一篇。说不敢,是因为HTTP/3表面看只是HTTP协议的第三个大版本,内核里却把传输层的底座整个换了——它不像HTTP/1.1到HTTP/2那样只在应用层做文章,而是直接把协议栈从TCP搬…

2026/10/19 4:09:35 阅读更多 →
开放式代码审查实战:从流程搭建到协作效率提升

开放式代码审查实战:从流程搭建到协作效率提升

我接手过好几个中型仓库,里面有大量“高危但能跑到上线”的代码:吞掉的异常、裸奔的权限校验、藏在注释里的临时逻辑。很多都能在上线前被拦下来,前提是有人在Review时真的盯住了。这也是我为什么想写这篇关于open-code-review文章的原因。这…

2026/10/19 4:09:35 阅读更多 →
开源代码评审工具 open-code-review:把 Code Review 变成可量化的工程习惯

开源代码评审工具 open-code-review:把 Code Review 变成可量化的工程习惯

提到 code review,不少团队的回答都是“我们在做”,但真去翻一遍仓库的合并记录,会发现大量 PR 都是一个人开发、另一个人在合并前点了通过。评审更像走流程,而不是讨论问题。我维护了一个叫 open-code-review 的开源项目&#xf…

2026/10/19 4:09:35 阅读更多 →
STM32F103ZET6循迹小车竞速方案:灰度传感器与PID控制实战

STM32F103ZET6循迹小车竞速方案:灰度传感器与PID控制实战

简介:面向智能车竞速与STM32嵌入式学习的循迹小车完整工程,以72MHz主频的STM32F103ZET6作为核心控制器,机械结构采用舵机加双编码电机,通过一字排列的灰度传感器阵列识别黑线,从而检测车身在直道、环岛、S弯和连续直角…

2026/10/19 4:09:35 阅读更多 →
开放式代码评审的完整实践指南:从机制到落地

开放式代码评审的完整实践指南:从机制到落地

代码评审这件事,我干了快十年,到现在还是会劝刚带团队的朋友一句:先把评审机制立起来,再谈什么敏捷流程、DevOps 文化。open-code-review 这个名字,听起来像某个开源库,本质上却代表了我这些年一直在推的做…

2026/10/19 4:09:35 阅读更多 →
LSTM原理详解与工程加速:从梯度消失到推理优化

LSTM原理详解与工程加速:从梯度消失到推理优化

最近在某个工业设备的时序预测项目里,我把LSTM重新捡起来用了一遍。说实话,这两年Transformer在序列任务上的声量确实大,很多新入行的同学一上来就研究注意力机制,反而把LSTM这个经典的循环结构给忽略了。但手头这个项目跑下来&am…

2026/10/19 4:08:35 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →