尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Python实现KMeans聚类算法:源码、数据集与实战避坑指南
简介这份资源面向机器学习入门者与数据挖掘方向的学习者提供了一套用Python实现的KMeans聚类算法完整方案可用于理解聚类分析从数据预处理、核心算法执行到结果可视化的全流程适合作为课程实验、算法练习或项目参考的实践素材。压缩包共收录246个文件约35.02MB其中以141个CSV数据集文件为主体配合16个Python程序文件承载算法逻辑另有43个PNG与2个JPG图表用于呈现聚类结果并附带少量文本说明与版本控制配置文件目录结构清晰、便于按模块查阅。目前已有62人学习下载。读者可从中获得可直接运行的聚类代码范例、多组实验数据以及配套可视化图表既能对照源码理解KMeans的迭代与收敛过程也能替换数据集快速验证不同参数下的聚类效果为后续数据挖掘研究提供可复用的参考工具。1. 从一堆散点到一个客户分群KMeans 到底能解决什么手里有一份用户行为表几千行、几十个字段老板要你「分个层出来」。你盯着屏幕第一反应可能是拍脑袋定阈值消费大于 500 算高价值小于 100 算低价值。问题是阈值定几个、定在哪全靠猜换一批数据就失效。KMeans 聚类算法就是干这个的它不需要你提前告诉它谁属于哪一类只根据样本之间的「距离」自动把相似的点拢到一起。这份 Python 实现 KMeans 聚类算法源码及数据集给的是一个能直接跑通的最小闭环——算法本体、可替换的数据集、以及一套能照着改的调用方式。适合两类人刚学完 Python 语法、想找一个完整小项目练手的入门者以及手头有分群、压缩、异常初筛需求想快速验证一版基线效果的从业者。它不解决「聚类一定有意义」这件事但能让你在半小时内看到结果、判断方向对不对。2. 拆开 KMeans 源码三个核心动作与手写实现2.1 为什么是「迭代两步」而不是一次算完KMeans 的直觉非常朴素先随便撒 k 个中心点然后反复做两件事——把每个样本分配给最近的中心再把每个中心挪到它名下样本的平均位置。这两步交替执行直到中心点不再明显移动。它之所以有效是因为每一步都在降低同一个目标函数所有样本到其所属中心的距离平方和也就是常说的 SSE误差平方和。这个值单调不增所以算法一定会收敛但收敛到的可能是局部最优不是全局最优。理解这一点很关键你后面遇到「每次跑出来结果不一样」根子就在这里不是代码写错了。源码里通常会把「分配」和「更新」拆成两个函数这样调试时能单独看某一步的输出。我一般会先确认距离用的是欧氏距离因为绝大多数场景默认就是它如果你的特征是经纬度或者概率分布直接套欧氏距离会翻车得先做特征处理。2.2 手写一版可调试的 KMeans下面这段是源码包里最核心的部分我按能直接运行的方式整理出来关键行都加了注释。它不依赖 sklearn方便你看清每一步在干什么。import numpy as np def euclidean_distance(a, b): # 逐元素求差、平方、求和、开方得到两点欧氏距离 return np.sqrt(np.sum((a - b) ** 2)) def assign_clusters(X, centers): # 为每个样本找最近的中心索引 labels [] for point in X: distances [euclidean_distance(point, c) for c in centers] labels.append(np.argmin(distances)) return np.array(labels) def update_centers(X, labels, k): # 按当前标签重新计算每个簇的均值作为新中心 new_centers [] for i in range(k): cluster_points X[labels i] if len(cluster_points) 0: # 空簇保护没有样本时保留原中心避免除零 new_centers.append(X[np.random.randint(0, len(X))]) else: new_centers.append(cluster_points.mean(axis0)) return np.array(new_centers) def kmeans(X, k, max_iter100, tol1e-4): # 随机选 k 个样本作为初始中心 idx np.random.choice(len(X), k, replaceFalse) centers X[idx] for i in range(max_iter): labels assign_clusters(X, centers) new_centers update_centers(X, labels, k) # 中心移动量小于 tol 就提前停止 shift np.sum([euclidean_distance(a, b) for a, b in zip(centers, new_centers)]) centers new_centers if shift tol: break return centers, labels逻辑上分四块距离函数、分配函数、更新函数、主循环。参数里k是簇数量必须你指定max_iter是最大迭代次数防止死循环tol是收敛阈值越小越精确但越慢。update_centers里那段空簇保护是血泪经验——当某个中心离所有样本都远可能一个样本都分不到直接求均值会报 nan源码里如果没处理跑真实数据时很容易崩。2.3 数据集怎么读、怎么喂进去源码包里的数据集一般是 CSV 或 txt常见结构是每行一个样本、每列一个特征。读取时要注意两件事一是跳过表头二是确认没有缺失值。下面这段是通用读法import numpy as np def load_data(path): # 假设文件无表头、以逗号分隔有表头就加 skiprows1 data np.loadtxt(path, delimiter,) # 简单清洗去掉含 nan 的行 data data[~np.isnan(data).any(axis1)] return data if __name__ __main__: X load_data(data.csv) centers, labels kmeans(X, k3) print(中心点, centers) print(前 10 个标签, labels[:10])delimiter要跟文件实际分隔符一致制表符就写\t。如果你的数据量很大np.loadtxt会偏慢换成pandas.read_csv再转values更稳。喂进模型前如果各列量纲差得远比如一列是年龄、一列是年收入一定要先标准化否则收入那一列会主导距离计算聚类结果基本只反映收入。3. 跑通第一版k 值选择、标准化与结果验证3.1 k 到底怎么定肘部法和轮廓系数k 是 KMeans 唯一必须人为指定的关键参数也是最容易拍脑袋的地方。常见做法是跑一串 k看 SSE 随 k 增大的下降曲线拐点处就是相对合适的值这叫肘部法。更客观一点用轮廓系数取值在 -1 到 1 之间越大说明簇内越紧、簇间越远。from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score from sklearn.preprocessing import StandardScaler X load_data(data.csv) X_scaled StandardScaler().fit_transform(X) # 标准化消除量纲影响 for k in range(2, 8): km KMeans(n_clustersk, n_init10, random_state42) labels km.fit_predict(X_scaled) sse km.inertia_ # 簇内误差平方和 score silhouette_score(X_scaled, labels) print(fk{k}, SSE{sse:.2f}, 轮廓系数{score:.3f})n_init10表示用不同初始中心跑 10 次取最优能明显缓解局部最优问题random_state固定后结果可复现方便你对比不同 k。看输出时别只盯 SSE 最小SSE 永远随 k 增大而减小k 等于样本数时 SSE 为 0那没有意义。要结合轮廓系数和业务可解释性一起判断。3.2 标准化不是可选项很多人第一次跑聚类结果里一个簇巨大、其余簇各一两个点八成是没做标准化。量纲大的特征在欧氏距离里占绝对权重等于你只按那一列在分。标准化把每列变成均值 0、方差 1让各特征公平参与。如果数据里有明显离群点标准化会被拉偏这时可以考虑先做分位数截断或者改用对异常值更稳健的 RobustScaler。3.3 结果怎么验证不是自嗨聚类没有标签验证要靠间接手段。除了轮廓系数我一般会做两件事一是把每个簇的样本数打出来看有没有极端不均衡二是把每个簇在各特征上的均值列成表人工读一遍看这个簇能不能用一句话描述。如果某个簇的特征均值跟整体均值几乎一样那这个簇大概率没有业务含义要么 k 选多了要么特征选得不对。检查项健康信号危险信号簇样本数各簇数量相对均衡某簇只有个位数样本轮廓系数大于 0.3 且随 k 平稳接近 0 或为负簇特征均值各簇差异明显可描述各簇均值几乎一致SSE 曲线有明显拐点一路平滑无拐点4. 避坑与排查五个真实翻车现场4.1 每次运行结果都不一样现象是同一份数据、同一个 k跑两次标签完全不同。原因是初始中心随机选落到了不同的局部最优。解决方式是固定random_state并把n_init调大让算法多试几组初始值取 SSE 最小的那组。手写版里对应的是多跑几次主循环、比较最终 SSE。4.2 出现空簇导致程序报 nan现象是运行中途中心点变成 nan或者某个簇一个样本都没有。原因是初始中心选得太偏或者 k 设得比实际类别数大太多。解决方式是在更新中心时加空簇保护重新随机选一个样本当中心更根本的是先用肘部法把 k 降到合理范围。4.3 结果对量纲极度敏感现象是加了某一列特征后聚类结果完全变样。原因是该列数值范围远大于其他列距离计算被它主导。解决方式是聚类前统一做标准化并且把量纲差异极大的特征要么剔除、要么先做对数变换。4.4 把类别型特征直接当数值喂进去现象是性别、城市这类字段参与距离计算结果诡异。原因是 KMeans 基于欧氏距离只适合连续数值特征。解决方式是类别特征先做独热编码或者改用 K-Prototypes 这类能处理混合类型的算法别硬套。4.5 数据量大时跑得极慢现象是几万行数据跑一次要几分钟甚至更久。原因是手写版用了双重循环复杂度是样本数乘 k 乘迭代次数。解决方式是改用 sklearn 的 KMeans底层是优化过的或者先用 MiniBatchKMeans 做小批量近似数据量再大就考虑先降采样再聚类。提示排查顺序建议固定为「先看数据有没有 nan 和量纲问题再看 k 和初始中心最后才怀疑算法实现」。多数翻车都出在前两步。5. 进阶技巧用 MiniBatch 和降维把 KMeans 用到生产边缘当数据从几千行涨到几十万行标准 KMeans 的每次迭代都要扫全量样本时间成本会变得难以接受。我一般会先上 MiniBatchKMeans它每次只用一小批样本更新中心速度快一个量级代价是结果略有波动。用法上几乎无缝替换from sklearn.cluster import MiniBatchKMeans mbk MiniBatchKMeans( n_clusters5, batch_size1024, # 每批样本数越大越接近标准版 n_init10, random_state42 ) labels mbk.fit_predict(X_scaled)batch_size是关键参数太小收敛快但结果抖太大就失去速度优势我通常从 1024 起步按数据规模上下调。另一个常用组合是先降维再聚类用 PCA 把几十维压到几维既提速又能顺带去掉噪声维度但要注意降维后距离的含义变了解释结果时得回到原始特征去看每个簇的均值。验证进阶版是否靠谱我的习惯是拿同一份数据分别跑标准版和 MiniBatch 版比较两者的 SSE 和轮廓系数差距在可接受范围内才敢用。最后留一个我自己的教训早期我图省事聚类前没固定随机种子给业务方演示时两次结果对不上当场被问住。从那以后我每次跑聚类都强制固定random_state并把标准化、k 值选择、结果验证走成固定三步再也没在演示环节翻过车。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

激光雷达接收芯片选型实战:APD、SiPM与SPAD阵列对比

激光雷达接收芯片选型实战:APD、SiPM与SPAD阵列对比

1. 这不是芯片参数表,而是一份激光雷达接收端的“实战选型手记”我干激光雷达硬件设计快八年了,从最早给扫地机器人配单点TOF模组,到后来做车载前向4D成像雷达的接收链路,踩过的坑比走过的桥还多。今天聊的这个标题——“激光雷达…

📅 2026/10/3 4:36:39
SpringBoot+Vue 项目申报管理系统源码实战解析

SpringBoot+Vue 项目申报管理系统源码实战解析

做项目申报管理系统的人,应该都经历过申报季那种兵荒马乱的阶段:通知发下去、材料收上来、格式五花八门、打回重报的信息散落在聊天记录里,评审打分靠纸质表格统计到半夜。这套基于SpringBootVueMyBatisMySQL的源码项目,就是冲着这…

📅 2026/10/3 4:36:39
QwenPaw本地部署与调用指南:从安装到批量处理

QwenPaw本地部署与调用指南:从安装到批量处理

1. 从零上手 QwenPaw:这个工具到底解决什么问题第一次听到 QwenPaw 这个名字,很多人会下意识把它和某个模型或者某个框架联系起来。实际上,QwenPaw 是一个面向本地化部署与调用的工具型项目,核心定位是让使用者能够在自己熟悉的开…

📅 2026/10/3 4:36:39
MORE NEWS

更多资讯

📰

C++多线程入门:std::thread线程创建、生命周期与参数传递详解

日常写C项目,只要一涉及高并发、毫秒级响应或者“一边下载一边渲染”这类需求,多线程就跑不掉。而在C里最直白、用得最多的线程接口,就是标准库自带的std::thread。这篇是系列第一篇文章,我不打算堆概念,直接把创建线程…

📰

仿真系统子系统交互的几何视角:从坐标到空间关系的设计实践

干这行这么多年,我越来越觉得,搞仿真系统的人分两种:一种是把子系统交互当成“接口对接”来做,定义好端口、数据类型、时序就算完事;另一种会多问一句——这些交互在空间上到底意味着什么?AFSim这种成熟仿真…

📰

Madeira 跨平台兼容方案:Wine + FEX-Emu + DXMT 在 ARM 与 iOS 上运行 Windows 应用

1. 从“Madeira”这个名字说起:它到底是什么第一次看到“Madeira”这个词,很多人第一反应是葡萄牙那个产葡萄酒的海岛,或者是一块叫马德拉的蛋糕。但在折腾跨平台兼容层的圈子里,Madeira 指的是一套围绕 Wine 构建的、面向移动端和…

📰

AFSim几何视角:坐标系、姿态与交互域如何驱动子系统正确交互

先说个这几年做仿真联调最深的体会:每个子系统单独跑都好好的,一合起来就出各种"灵异事件",最后查到原因,十有七八不是接口协议的问题,而是几何关系上的问题。你的坐标系基准和我的差了半度,他用…

📰

合成数据实战:从生成到评估的完整链路与避坑指南

1. 从"数据不够用"说起:合成数据到底在解决什么问题做过模型训练的人都有一个共同的痛:数据永远不够。尤其是当你需要训练一个稍微像样点的深度学习模型时,真实数据的获取成本高得离谱——标注要钱、采集要时间、清洗要人力&#x…

📰

OpenCode:终端里的开源AI编程代理,从安装到模型接入的实战指南

上个月我把一个老项目的错误码模块丢给终端里的AI助手去重构,它一口气改了12个文件,全局搜索、交叉引用、连注释风格都跟着项目走了。整个过程我没有打开过一次IDE,只在终端里和它对话,这个AI助手就是OpenCode。先把定义说清楚&am…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬