ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

模糊C均值聚类源码解析:从K-Means过渡到FCM实战

模糊C均值聚类源码解析:从K-Means过渡到FCM实战 简介这份源码包面向数据挖掘与机器学习初学者聚焦模糊C均值FCM聚类算法的Python实现与可视化适合正在学习聚类、需要动手复现算法的学生和开发者。压缩包共29个文件约638KB包含4个py脚本、2个ipynb笔记本、8张png可视化图、3个txt说明及csv、xlsx数据文件等覆盖数据加载、模型训练、结果输出与图像绘制等环节。源码中自定义了FCM的隶属度更新与类别中心迭代流程并借助NumPy、Pandas、Matplotlib完成数据处理与二维散点展示同时保留KMeans作为对照便于观察模糊系数m与类别数C对聚类效果的影响。已有167人学习读者可据此理解FCM目标函数、迭代停止条件与隶属度可视化方法并在此基础上修改参数、替换数据集完成从算法原理到代码落地的完整实践。1. 拿到一份 FCM 聚类源码先别急着跑搞清楚它能干什么很多做数据分析的朋友第一次接触模糊C均值都是被 K-Means 在重叠样本上翻车逼过来的。K-Means 硬性把每个点划给唯一簇遇到边界模糊、噪声多的数据聚类结果就飘得厉害。这份「模糊C均值做聚类并做可视化源码.zip」正好补上这个短板它用 Python 实现了 FCM 算法允许一个样本以不同隶属度同时归属多个类别还配了完整的可视化输出。压缩包里包含 dataLoader.py、Trainer.py、vision.py、run.py 四个核心脚本外加一份聚类数据.xlsx 和 results 目录下的散点图、损失曲线、聚类结果 CSV。适合正在做课程设计、数据分析项目或者想从 K-Means 过渡到模糊聚类的从业者。你拿到手就能跑但前提是先把环境、数据格式和参数含义对齐否则大概率卡在第一步。2. 拆开源码包四个脚本各管什么数据怎么流转2.1 模块分工与调用链这个项目的结构很清晰没有过度封装适合拿来改。run.py是入口负责串联整个流程dataLoader.py管数据读取和预处理Trainer.py是 FCM 算法的核心实现包含隶属度矩阵更新和聚类中心迭代vision.py负责画图输出散点图、损失曲线和每个类别的单独分布图。dataset目录下放的是聚类数据.xlsxresults目录是运行后的输出位置里面已经预置了cluster_results.csv、result.txt以及多张 PNG 图片说明作者跑通过一轮你可以拿这些结果做对照。调用链是run.py调dataLoader读 Excel → 数据传给Trainer做 FCM 迭代 → 迭代完把标签和隶属度交给vision画图 → 同时把结果写进results。整个流程没有用 sklearn 的 FCMsklearn 也没有官方 FCM而是手写实现这对理解算法细节反而更友好。2.2 环境依赖与版本对齐压缩包里有一份环境需求.txt这是第一手线索。虽然具体内容需要你解压后查看但根据代码结构和.pyc文件名里的cpython-38可以确定作者用的是 Python 3.8。常见做法是建一个干净虚拟环境把依赖锁在相近版本避免 numpy 或 pandas 大版本差异导致FutureWarning甚至 API 报错。# 创建虚拟环境Python 3.8 与 pyc 文件匹配 python3.8 -m venv fcm_env source fcm_env/bin/activate # Windows 用 fcm_env\Scripts\activate # 安装核心依赖版本按环境需求.txt 调整 pip install numpy pandas matplotlib openpyxl scikit-learn这里openpyxl容易被漏掉因为数据是.xlsx格式pandas 读 Excel 必须靠它。scikit-learn在项目里可能用于对比 K-Means 或者做标准化不装的话 import 阶段就会断。装完先别急着python run.py下一步要确认数据格式。2.3 数据加载与预处理逻辑dataLoader.py的职责是把 Excel 转成 numpy 数组并做必要的清洗。FCM 对量纲敏感如果一列是年龄0-100另一列是收入0-100000距离计算会被大数值主导。常见做法是做标准化或归一化。你可以打开dataLoader.py看它有没有StandardScaler或手写的 min-max 归一化。如果没有建议自己补上否则聚类中心会偏向大尺度特征。# dataLoader.py 中典型的数据读取与预处理片段 import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler def load_data(filepath): df pd.read_excel(filepath) # 假设最后一列是标签或无关列特征列在前 features df.iloc[:, :-1].values.astype(float) # 标准化FCM 基于欧氏距离量纲统一是前提 scaler StandardScaler() features_scaled scaler.fit_transform(features) return features_scaled这段逻辑说明iloc[:, :-1]取特征列astype(float)防止整数除法或类型报错。标准化用fit_transform而不是transform因为这是训练集全量。如果你的数据里有缺失值StandardScaler会直接报错需要先fillna或dropna。参数上StandardScaler按列减均值除标准差适合近似高斯分布的数据如果数据有极端离群值换成MinMaxScaler更稳。3. 跑通 FCM 核心隶属度矩阵、模糊系数与迭代停止条件3.1 FCM 与 K-Means 的本质差异K-Means 的隶属度只有 0 或 1一个样本要么属于 A 簇要么属于 B 簇。FCM 把隶属度推广到 [0,1] 连续区间用隶属度矩阵 U 表示每个样本对每个簇的归属程度且每个样本对所有簇的隶属度之和为 1。目标函数是J ΣΣ(u_ij^m * ||x_i - c_j||^2)其中 m 是模糊系数控制隶属度的模糊程度。m 越大隶属度越分散m 趋近 1 时FCM 退化成 K-Means。常见取值是 m2这也是Trainer.py里最可能出现的默认值。这个差异带来的实际好处是当两个簇有重叠区域时FCM 不会强行切一刀而是给出「这个点 60% 属于簇 040% 属于簇 1」这样的软判决。对于后续做风险分层或推荐系统这种概率式输出比硬标签更有信息量。3.2 隶属度更新与聚类中心迭代Trainer.py的核心是一个 while 循环每轮先更新隶属度再更新聚类中心直到目标函数变化小于阈值或达到最大迭代次数。下面是根据项目结构还原的典型实现# Trainer.py 中 FCM 迭代的核心逻辑 import numpy as np class FCM: def __init__(self, n_clusters3, m2, max_iter150, tol1e-5): self.n_clusters n_clusters # 类别数 C self.m m # 模糊系数 self.max_iter max_iter # 最大迭代次数 self.tol tol # 停止阈值 def fit(self, X): n_samples X.shape[0] # 初始化隶属度矩阵每行和为 1 U np.random.rand(n_samples, self.n_clusters) U U / U.sum(axis1, keepdimsTrue) for i in range(self.max_iter): U_old U.copy() # 计算聚类中心 c_j Um U ** self.m centers (Um.T X) / Um.sum(axis0)[:, None] # 计算距离矩阵 dist np.linalg.norm(X[:, None] - centers[None, :], axis2) dist np.fmax(dist, 1e-10) # 防止除零 # 更新隶属度 power 2 / (self.m - 1) ratio (1 / dist) ** power U ratio / ratio.sum(axis1, keepdimsTrue) # 检查收敛 if np.linalg.norm(U - U_old) self.tol: break self.centers centers self.U U self.labels np.argmax(U, axis1) return self逻辑说明U ** self.m是隶属度的 m 次方用于加权计算中心。np.fmax(dist, 1e-10)是血泪经验——当某个样本恰好落在聚类中心上时距离为 0倒数会变成 inf整个矩阵就废了。power 2/(m-1)是 FCM 的标准推导结果m2 时 power2。停止条件用隶属度矩阵的范数变化比用目标函数更直接。参数上n_clusters需要根据业务定max_iter150对多数中小数据集够用tol1e-5是精度和速度的折中。3.3 结果输出与可视化脚本vision.py负责把Trainer产出的标签和隶属度画出来。从results目录的文件名看作者输出了scatter.png总体散点图、loss.png目标函数下降曲线、以及DST_类别0.png、PTDTC_类别1.png这类按类别拆分的图。这说明数据里可能有两个不同的子集或两种标签体系DST 和 PTDTC 是数据来源的缩写。# vision.py 中散点图与损失曲线的典型画法 import matplotlib.pyplot as plt def plot_scatter(X, labels, centers, save_pathresults/scatter.png): plt.figure(figsize(8, 6)) scatter plt.scatter(X[:, 0], X[:, 1], clabels, cmapviridis, alpha0.6) plt.scatter(centers[:, 0], centers[:, 1], cred, markerX, s200, labelCenters) plt.colorbar(scatter, labelCluster) plt.legend() plt.title(FCM Clustering Result) plt.savefig(save_path, dpi150) plt.close() def plot_loss(loss_history, save_pathresults/loss.png): plt.figure(figsize(8, 5)) plt.plot(loss_history, markero, markersize3) plt.xlabel(Iteration) plt.ylabel(Objective Function J) plt.title(FCM Convergence Curve) plt.grid(True, alpha0.3) plt.savefig(save_path, dpi150) plt.close()alpha0.6让重叠点可见markerX标出聚类中心dpi150保证输出图够清晰。损失曲线是判断有没有收敛的后悔药——如果曲线还在明显下降就到了max_iter说明迭代次数不够需要调大。如果曲线震荡可能是 m 太小或数据没标准化。4. 避坑与排查跑 FCM 最容易翻车的五个地方4.1 现象运行报ModuleNotFoundError: No module named openpyxl原因pandas 读.xlsx需要 openpyxl 引擎环境需求里可能没显式写。 解决pip install openpyxl如果还报错检查 pandas 版本是否过旧pip install --upgrade pandas。4.2 现象聚类结果每次运行都不一样原因FCM 初始化隶属度矩阵是随机的没有设随机种子。 解决在Trainer.py开头加np.random.seed(42)或者在fit里用固定初始化。生产环境建议跑多次取最优目标函数值。4.3 现象所有样本被分到同一个簇原因模糊系数 m 设得过大比如 m5隶属度过于均匀argmax后全指向同一类或者数据没标准化某个特征主导了距离。 解决把 m 调回 1.5~2.5 区间先做标准化再聚类。检查dataLoader.py是否漏了归一化步骤。4.4 现象损失曲线不下降或震荡原因学习率式的更新不存在于 FCM震荡通常是因为距离矩阵出现极小值导致隶属度爆炸。 解决确认代码里有np.fmax(dist, 1e-10)这类防除零保护。另外检查数据里有没有重复点或 NaNdropna后再跑。4.5 现象results目录图片是空的或只有坐标轴原因vision.py在run.py里被调用时数据可能还没传进去或者plt.savefig之前调了plt.show()导致阻塞。 解决确保run.py里先fit再plot把plt.show()注释掉只保留savefig。检查results目录是否存在不存在先os.makedirs(results, exist_okTrue)。5. 调参进阶用隶属度做软判决把聚类结果用出额外价值跑通默认参数只是起点。FCM 真正比 K-Means 多出来的东西是隶属度矩阵 U很多人跑完只取argmax拿硬标签等于把 FCM 当 K-Means 用浪费了模糊信息。我一般会做两件事一是用隶属度熵来评估聚类的不确定性二是把高隶属度的样本作为置信样本低隶属度的挑出来人工复核或做后续规则判断。# 利用隶属度矩阵做不确定性分析 import numpy as np def uncertainty_analysis(U): # 隶属度熵熵越高样本归属越模糊 entropy -np.sum(U * np.log(U 1e-10), axis1) # 最大隶属度低于阈值的样本需要关注 max_membership np.max(U, axis1) uncertain_mask max_membership 0.6 print(f不确定样本数: {uncertain_mask.sum()} / {len(U)}) return entropy, uncertain_masknp.log(U 1e-10)防止 log(0)。max_membership 0.6是我常用的阈值低于它说明这个样本对任何簇的归属都不超过 60%属于边界样本。你可以把这些样本单独导出结合业务判断是噪声还是真实过渡态。另一个技巧是拿 FCM 的聚类中心做新数据的软分配。训练好的centers可以保存下来新样本进来时只更新隶属度不更新中心相当于一个轻量级的模糊分类器。这在数据流式到达的场景里比重新训练整个模型省事得多。参数选择上n_clusters可以用肘部法辅助跑 C2 到 C10看目标函数 J 的下降拐点。但 FCM 的 J 本身随 C 增大单调下降所以更常用的是看隶属度熵的均值或者轮廓系数。m的取值对结果影响很大m2 是默认起点如果数据噪声特别多可以试 m2.5 或 3让隶属度更平滑如果希望结果接近硬聚类m1.2 到 1.5 之间。从那以后我每次拿到一份聚类源码都强制先跑一遍默认参数把results里的损失曲线和散点图看一遍确认收敛和分布正常再动数据预处理和参数。这份 FCM 源码结构干净改起来不费劲适合拿来当模糊聚类的实验底稿。希望帮到你。本文还有配套的精品资源点击获取
返回列表