尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

模糊C均值聚类(FCM)原理详解与Python实战:从隶属度到图像分割

模糊C均值聚类(FCM)原理详解与Python实战:从隶属度到图像分割 1. 项目概述从“非黑即白”到“亦此亦彼”的认知升级在数据分析和模式识别的世界里我们习惯了“非此即彼”的二元划分。一个样本要么属于A类要么属于B类界限分明。但现实世界往往要复杂得多。想象一下你要对一片森林里的树木进行分类一棵树可能70%像松树30%像杉树硬把它归为某一类总会丢失一部分信息。模糊聚类特别是模糊C均值聚类就是用来处理这种“模糊性”的利器。它不追求绝对的归属而是为每个样本赋予一个属于各个类别的“隶属度”这个值在0到1之间表示样本属于该类的“可能性”或“程度”。FCM不是数学建模竞赛中的新贵但它是一种强大而基础的工具尤其适合处理那些类别边界不清、存在过渡状态的数据比如图像分割、市场细分、地质勘探甚至是医疗诊断。对于刚接触建模的朋友来说理解FCM是理解“软计算”和现实世界复杂性问题建模的绝佳起点。它能帮你跳出非黑即白的思维定式用更细腻的视角去解构数据。2. FCM核心原理隶属度与聚类中心的舞蹈要搞懂FCM得先掰扯清楚它和传统硬聚类比如K-Means的根本区别。K-Means是“霸道总裁”一个样本必须且只能属于一个簇计算时只考虑簇内样本的均值。FCM则是“端水大师”它承认世界的复杂性允许一个样本以不同的程度同时属于多个簇。这个“程度”就是隶属度。2.1 模糊集合与隶属度函数这一切的基石是模糊数学。在经典集合论里一个元素要么属于集合A要么不属于特征函数值非0即1。模糊集合扩展了这个概念它的隶属度函数可以取[0, 1]之间的任何值。比如“高个子”这个模糊集合身高2米的人隶属度可能是1身高1.75米的人隶属度可能是0.7身高1.6米的人隶属度可能是0.2。FCM就是将这个思想用在了聚类上每个簇都是一个模糊集合每个样本对于每个簇都有一个隶属度。2.2 FCM的目标函数与迭代优化FCM的目标是找到一组聚类中心并确定每个样本对每个中心的隶属度使得一个特定的目标函数最小化。这个目标函数看起来有点复杂但理解其组成部分是关键J Σ从i1到C Σ从k1到N (u_ik)^m * ||x_k - v_i||^2别被公式吓到我们来拆解一下C: 聚类的数目这是你需要事先指定的和K-Means一样。N: 样本的总数。u_ik: 第k个样本对第i个簇的隶属度满足两个条件1) 对于任意样本k它对所有簇的隶属度之和为12) 每个隶属度值在0到1之间。m:模糊加权指数也叫平滑参数。这是FCM的灵魂参数必须大于1通常取1.5到3.0。m越大聚类结果越模糊隶属度会更均匀地分散m越接近1结果越接近硬聚类。它控制了隶属度的“软硬”程度。x_k: 第k个样本的数据向量。v_i: 第i个簇的聚类中心。||x_k - v_i||^2: 样本k到中心i的欧氏距离的平方也可以使用其他距离度量。这个目标函数J的物理意义很直观它希望所有样本点到所有聚类中心的加权距离平方和最小。这里的“权重”就是隶属度的m次方(u_ik)^m。一个样本离某个中心越远如果它还对这个中心有较高的隶属度就会对目标函数产生很大的“惩罚”因此算法会倾向于给远处的样本分配较低的隶属度。FCM通过交替优化来求解这个最小化问题这是一个非常优雅的迭代过程初始化随机初始化或根据先验知识初始化一组聚类中心V {v_1, v_2, ..., v_C}并随机初始化隶属度矩阵U需满足隶属度的和为1的条件。更新隶属度固定中心优化U根据当前聚类中心计算每个样本对每个新中心的隶属度。公式推导自拉格朗日乘子法结果是u_ik 1 / Σ从j1到C (||x_k - v_i|| / ||x_k - v_j||)^(2/(m-1))这个公式很美样本k对簇i的隶属度取决于它到簇i的距离与到所有簇距离的相对大小。距离越近隶属度越高。更新聚类中心固定U优化V根据新的隶属度矩阵重新计算每个簇的中心。公式是v_i Σ (u_ik)^m * x_k / Σ (u_ik)^m可以看到聚类中心不再是所有样本的简单平均而是所有样本的加权平均权重就是(u_ik)^m。隶属度高的样本对中心的位置影响更大。迭代判断计算更新前后聚类中心的变化或目标函数J的变化。如果变化小于一个预设的很小阈值如1e-5则认为算法已经收敛停止迭代否则跳回第2步继续迭代。这个过程就像一场精心编排的双人舞隶属度矩阵U和聚类中心V交替引领每一步都朝着整体目标函数更小的方向前进直到找到平衡点。注意模糊加权指数m的选择至关重要。m2是一个最常用、也往往效果不错的默认值。但在实际应用中可能需要通过有效性指标如划分系数、划分熵等来辅助选择。m太小如1.1会导致算法对初始值异常敏感且容易陷入局部最优m太大如3则会使聚类结果过于模糊失去区分度。3. 手把手实现从理论到Python代码理解了原理我们来看看如何用代码实现它。这里我们用最经典的Python科学计算栈NumPy。为了对比我们也会用scikit-fuzzy这个专门的模糊逻辑库来实现。3.1 数据准备与可视化我们先人造一个简单的二维数据集它包含三个部分重叠的高斯分布簇这样能很好地展示模糊聚类的优势。import numpy as np import matplotlib.pyplot as plt # 设置随机种子保证可复现 np.random.seed(42) # 生成三个有重叠的簇 cluster1 np.random.randn(100, 2) np.array([2, 2]) cluster2 np.random.randn(100, 2) np.array([8, 3]) cluster3 np.random.randn(100, 2) np.array([5, 8]) # 合并数据 X np.vstack([cluster1, cluster2, cluster3]) # 可视化原始数据 plt.figure(figsize(8, 6)) plt.scatter(X[:, 0], X[:, 1], s30, alpha0.6, cgray, edgecolorsk) plt.title(原始数据分布三个有重叠的簇) plt.xlabel(特征 1) plt.ylabel(特征 2) plt.grid(True, alpha0.3) plt.show()3.2 自实现FCM核心算法自己实现一遍算法是对原理最好的消化。下面是FCM核心迭代过程的代码def fcm_custom(X, n_clusters3, m2.0, max_iter100, error1e-5, random_state42): 自实现模糊C均值聚类算法 参数: X: 输入数据形状 (n_samples, n_features) n_clusters: 聚类数目 m: 模糊加权指数必须 1 max_iter: 最大迭代次数 error: 停止迭代的阈值中心点变化 random_state: 随机种子 返回: centers: 最终聚类中心形状 (n_clusters, n_features) U: 最终隶属度矩阵形状 (n_clusters, n_samples) history_J: 每次迭代的目标函数值记录用于观察收敛 np.random.seed(random_state) n_samples, n_features X.shape # 1. 随机初始化隶属度矩阵U (满足每列和为1) U np.random.rand(n_clusters, n_samples) U U / np.sum(U, axis0, keepdimsTrue) # 归一化使每个样本的隶属度和为1 # 记录目标函数历史 history_J [] for iteration in range(max_iter): # 2. 计算聚类中心 V_i Σ(u_ik^m * x_k) / Σ(u_ik^m) U_m U ** m # 计算隶属度的m次方 centers np.dot(U_m, X) / np.sum(U_m, axis1, keepdimsTrue) # 3. 计算距离矩阵 (n_clusters, n_samples) # 使用欧氏距离避免循环利用广播机制 # 扩展维度以便广播计算: centers[:, None, :] 形状 (C, 1, F), X[None, :, :] 形状 (1, N, F) distance np.sqrt(np.sum((centers[:, None, :] - X[None, :, :]) ** 2, axis2)) # 防止除零错误将零距离替换为一个极小值 distance np.fmax(distance, 1e-8) # 4. 更新隶属度矩阵 U_ik 1 / Σ_j (d_ik / d_jk)^(2/(m-1)) # 计算距离比值的幂次项 power 2.0 / (m - 1) denominator np.sum((distance[:, :, None] / distance[None, :, :]) ** power, axis1) U_new 1.0 / denominator # 5. 计算目标函数值 J Σ_i Σ_k (u_ik^m * d_ik^2) J np.sum(U_m * (distance ** 2)) history_J.append(J) # 6. 检查收敛条件隶属度矩阵的最大变化量 U_change np.max(np.abs(U_new - U)) if U_change error: print(f算法在 {iteration 1} 次迭代后收敛。) break U U_new else: print(f达到最大迭代次数 {max_iter}。) return centers, U, np.array(history_J)3.3 使用现成库快速实现对于实际项目我们更推荐使用成熟的库比如scikit-fuzzy它经过优化且功能更全。# 安装 scikit-fuzzy pip install scikit-fuzzyimport skfuzzy as fuzz # 使用skfuzzy的cmeans函数 # 注意cmeans函数要求数据是 (n_features, n_samples) 格式需要转置 cntr, U_sk, J_history, _, _, _, _ fuzz.cluster.cmeans( X.T, # 数据形状 (n_features, n_samples) c3, # 聚类数目 m2.0, # 模糊指数 error1e-5, # 停止阈值 maxiter100, # 最大迭代次数 initNone # 自动初始化 ) # cntr是中心点需要转置回来与我们的格式一致 centers_sk cntr.T print(skfuzzy 计算得到的中心点:\n, centers_sk)3.4 结果可视化与分析得到隶属度矩阵U后我们如何解读和展示结果一个样本的最终“硬”分类可以取它隶属度最高的那个簇。但模糊聚类的魅力在于那个连续的隶属度本身。def visualize_fcm_results(X, centers, U, title_suffix): 可视化FCM聚类结果。 左图根据最大隶属度进行硬划分着色。 右图用颜色强度透明度和大小表示样本对某个簇例如簇0的隶属度。 # 根据最大隶属度确定每个样本的“主要”簇标签 hard_labels np.argmax(U, axis0) fig, axes plt.subplots(1, 2, figsize(14, 6)) # 左图硬划分结果 colors_hard [red, blue, green] for i in range(centers.shape[0]): mask (hard_labels i) axes[0].scatter(X[mask, 0], X[mask, 1], s50, alpha0.6, ccolors_hard[i], edgecolorsk, labelfCluster {i}) axes[0].scatter(centers[:, 0], centers[:, 1], s300, marker*, cgold, edgecolorsblack, linewidth2, labelCenters) axes[0].set_title(f硬划分结果 (基于最大隶属度) {title_suffix}) axes[0].set_xlabel(特征 1) axes[0].set_ylabel(特征 2) axes[0].legend() axes[0].grid(True, alpha0.3) # 右图展示对第一个簇的隶属度模糊性 # 用点的大小和透明度表示隶属度u_i0 membership_to_cluster0 U[0, :] scatter axes[1].scatter(X[:, 0], X[:, 1], s30 membership_to_cluster0*100, # 大小反映隶属度 cmembership_to_cluster0, cmapReds, alpha0.7, # 颜色和透明度反映隶属度 edgecolorsk, linewidth0.5) axes[1].scatter(centers[:, 0], centers[:, 1], s300, marker*, cgold, edgecolorsblack, linewidth2) axes[1].set_title(f对簇0的隶属度模糊性展示{title_suffix}) axes[1].set_xlabel(特征 1) axes[1].set_ylabel(特征 2) plt.colorbar(scatter, axaxes[1], label对簇 0 的隶属度) axes[1].grid(True, alpha0.3) plt.tight_layout() plt.show() # 使用自实现算法的结果进行可视化 centers_custom, U_custom, J_history_custom fcm_custom(X, n_clusters3, m2.0) visualize_fcm_results(X, centers_custom, U_custom, title_suffix(自实现)) # 绘制目标函数收敛曲线 plt.figure(figsize(8, 4)) plt.plot(J_history_custom, markero, linestyle-, linewidth2, markersize4) plt.title(FCM目标函数J在迭代中的收敛过程) plt.xlabel(迭代次数) plt.ylabel(目标函数 J 的值) plt.grid(True, alpha0.3) plt.show()运行这段代码你会看到两张图。左图看起来和K-Means的结果可能差不多但右图揭示了本质区别位于簇与簇交界区域的点其对某个簇比如红色簇的隶属度是渐变的颜色和大小在变化而不是非0即1。这正是模糊聚类的价值所在。实操心得在自实现距离计算时我最初使用了双层循环在样本量稍大时1000就慢得无法忍受。后来改用NumPy的广播机制centers[:, None, :] - X[None, :, :]代码简洁了速度提升了两个数量级。这提醒我们在数据科学中善用数组运算避免显式循环是写出高效代码的关键。4. 关键参数调优与有效性评估FCM不像深度学习有那么多超参数但关键的几个选不好结果可能南辕北辙。4.1 模糊指数m的影响m控制着聚类的“模糊程度”。我们可以通过一个实验来直观感受m_values [1.2, 1.6, 2.0, 2.5, 3.0, 3.5] fig, axes plt.subplots(2, 3, figsize(15, 10)) axes axes.ravel() for idx, m in enumerate(m_values): _, U_temp, _ fcm_custom(X, n_clusters3, mm, max_iter150) # 计算划分系数PC和划分熵PE PC np.sum(U_temp ** 2) / X.shape[0] # 划分系数值越大越清晰 PE -np.sum(U_temp * np.log(U_temp 1e-8)) / X.shape[0] # 划分熵值越小越清晰 hard_labels np.argmax(U_temp, axis0) for i in range(3): mask (hard_labels i) axes[idx].scatter(X[mask, 0], X[mask, 1], s30, alpha0.6, labelfC{i}) axes[idx].set_title(fm{m}\nPC{PC:.3f}, PE{PE:.3f}) axes[idx].set_xlabel(特征1) axes[idx].set_ylabel(特征2) axes[idx].legend(locupper right, fontsizesmall) axes[idx].grid(True, alpha0.3) plt.tight_layout() plt.show()观察结果你会发现m1.2结果非常接近硬聚类边界分明PC值高PE值低。m2.0模糊性适中能很好地反映重叠区域的过渡状态。m3.5聚类结果非常模糊不同簇的颜色几乎混在一起PC值很低PE值很高几乎失去了分类意义。如何选择m没有绝对标准。通常从m2开始尝试。一个经验法则是对于噪声较多、簇结构非常不清晰的数据可以适当增大m如2.5以增强算法的鲁棒性对于簇结构相对清晰的数据使用较小的m如1.5-2.0可以获得更明确的划分。可以通过观察PC和PE曲线选择PC值较大且PE值较小的m或者使用后续介绍的Xie-Beni指数等综合指标。4.2 聚类数目C的确定和K-Means一样确定最佳的簇数C是个挑战。除了经典的肘部法则看目标函数J随C变化的拐点和轮廓系数需先硬划分外模糊聚类有自己特有的有效性指标划分系数PC (1/N) * Σ_i Σ_k (u_ik^2)。PC值越接近1说明隶属度越倾向于0或1聚类越“清晰”。但PC会随着C增大而单调递增因此通常用于比较相同C下不同m值的效果。划分熵PE - (1/N) * Σ_i Σ_k [u_ik * log(u_ik)]。PE值越小聚类越清晰。同样存在对C的单调性问题。Xie-Beni 指数XB [Σ_i Σ_k (u_ik^m * ||x_k - v_i||^2)] / (N * min_{i≠j} ||v_i - v_j||^2)。这个指标同时考虑了类内紧密度分子和类间分离度分母。XB值越小表示聚类效果越好类内紧凑类间分离。XB指数被认为是比较可靠的一个指标。我们可以编写一个函数来计算不同C下的XB指数def compute_xie_beni_index(X, centers, U, m): 计算Xie-Beni聚类有效性指数。 返回值越小聚类效果越好。 n_clusters, n_samples U.shape # 计算类内紧密度目标函数J distance np.sqrt(np.sum((centers[:, None, :] - X[None, :, :]) ** 2, axis2)) compactness np.sum((U ** m) * (distance ** 2)) # 计算最小类间距离 min_center_dist np.inf for i in range(n_clusters): for j in range(i1, n_clusters): dist_ij np.linalg.norm(centers[i] - centers[j]) if dist_ij min_center_dist: min_center_dist dist_ij # 防止除零 if min_center_dist 1e-10: min_center_dist 1e-10 separation n_samples * (min_center_dist ** 2) xb_index compactness / separation return xb_index # 尝试不同的C值 c_range range(2, 8) xb_indices [] for C in c_range: centers_temp, U_temp, _ fcm_custom(X, n_clustersC, m2.0, max_iter150) xb compute_xie_beni_index(X, centers_temp, U_temp, m2.0) xb_indices.append(xb) print(f簇数 C{C}: Xie-Beni 指数 {xb:.4f}) # 可视化 plt.figure(figsize(8, 5)) plt.plot(c_range, xb_indices, bo-, linewidth2, markersize8) plt.xlabel(聚类数目 C) plt.ylabel(Xie-Beni 指数) plt.title(Xie-Beni指数随聚类数目的变化值越小越好) plt.grid(True, alpha0.3) plt.xticks(c_range) plt.show()对于我们的示例数据你可能会发现当C3时XB指数达到一个明显的低点之后开始上升或波动这提示3可能是一个合适的聚类数目。注意事项这些指标都是启发式的并非绝对真理。在实际项目中必须结合业务背景和可视化结果进行综合判断。例如在客户分群中最终分多少群可能需要考虑市场策略的可操作性如5-7群比较易于管理而不仅仅是数学上的最优。5. 实战进阶图像分割与特征工程FCM不仅用于简单的点集聚类它在图像处理、生物信息学等领域有广泛应用。我们以经典的图像分割为例看看如何将FCM应用于像素聚类。5.1 基于颜色特征的图像模糊分割图像中的每个像素可以看作是一个5维向量(R, G, B, x, y)即颜色信息和空间位置信息。用FCM对这些像素进行聚类可以实现图像分割。from skimage import data, io import matplotlib.pyplot as plt # 加载一张示例图片 image data.astronaut() # 或使用 io.imread(your_image.jpg) height, width, channels image.shape print(f图像尺寸: {height}x{width}, 通道数: {channels}) # 将图像数据重塑为 (像素数, 特征数) # 特征包括R, G, B 和 归一化的坐标 (x, y) pixels image.reshape(-1, 3).astype(float) / 255.0 # 颜色归一化到[0,1] # 创建空间坐标网格并归一化 xx, yy np.meshgrid(np.arange(width), np.arange(height)) xx_norm xx.reshape(-1, 1) / float(width) # 归一化到[0,1] yy_norm yy.reshape(-1, 1) / float(height) # 合并颜色和空间特征 # 可以调整空间特征的权重控制空间连续性对分割的影响 spatial_weight 0.5 # 空间特征权重越大分割区域越紧凑 X_img np.hstack([pixels, spatial_weight * xx_norm, spatial_weight * yy_norm]) print(f特征矩阵形状: {X_img.shape}) # 由于像素数巨大我们采样一部分进行计算以加快演示速度 sample_ratio 0.1 # 采样10%的像素 np.random.seed(42) sample_indices np.random.choice(X_img.shape[0], sizeint(X_img.shape[0]*sample_ratio), replaceFalse) X_sample X_img[sample_indices, :] # 使用skfuzzy进行FCM聚类在样本上 cntr_img, U_img, _, _, _, _, _ fuzz.cluster.cmeans( X_sample.T, c4, m2.0, error1e-5, maxiter100, initNone ) # 预测所有像素的隶属度使用距离公式避免重新运行整个聚类 # 计算所有像素到聚类中心的距离 centers_img cntr_img.T distances np.zeros((X_img.shape[0], centers_img.shape[0])) for i in range(centers_img.shape[0]): distances[:, i] np.sqrt(np.sum((X_img - centers_img[i])**2, axis1)) distances np.fmax(distances, 1e-8) # 根据距离计算所有像素的隶属度 power 2.0 / (2.0 - 1) # m2.0 U_all 1.0 / np.sum((distances[:, :, None] / distances[:, None, :]) ** power, axis2) # 根据最大隶属度获取每个像素的硬标签 segmented_labels np.argmax(U_all, axis1) # 将标签映射回图像形状 segmented_map segmented_labels.reshape(height, width) # 可视化结果 fig, axes plt.subplots(1, 3, figsize(15, 5)) axes[0].imshow(image) axes[0].set_title(原始图像) axes[0].axis(off) axes[1].imshow(segmented_map, cmaptab20c) # 使用分类色彩图 axes[1].set_title(FCM分割结果硬标签) axes[1].axis(off) # 可以选择显示某个簇的隶属度图模糊输出 membership_for_cluster0 U_all[:, 0].reshape(height, width) im3 axes[2].imshow(membership_for_cluster0, cmaphot) axes[2].set_title(对“天空”簇的隶属度模糊输出) axes[2].axis(off) plt.colorbar(im3, axaxes[2], fraction0.046, pad0.04) plt.tight_layout() plt.show()在这个例子中通过引入空间坐标(x, y)作为特征并赋予其权重spatial_weight我们可以控制分割区域的紧凑性和连续性。权重越大算法越倾向于将空间位置相近的像素聚在一起分割结果中的区域会更平滑、更少“椒盐噪声”。5.2 特征权重与选择在实际应用中特征工程对FCM效果的影响巨大。并非所有特征都同等重要。特征标准化/归一化由于FCM使用欧氏距离量纲不同的特征会主导距离计算。例如像素的x坐标范围是0-1000而RGB颜色范围是0-255如果不处理空间信息将完全压倒颜色信息。必须进行标准化Z-score或归一化Min-Max到[0,1]。特征加权有时我们知道某些特征更重要。可以在计算距离时引入权重向量W计算加权欧氏距离d sqrt( Σ w_j * (x_j - v_j)^2 )。这允许我们给颜色特征更高的权重或者给纹理特征更低的权重。特征选择对于高维数据可以使用PCA主成分分析或领域知识进行降维去除噪声和冗余特征不仅能提升速度还能改善聚类效果。实操心得在图像分割项目中我最初只用了RGB颜色特征结果分割区域非常破碎同一个物体的不同部分因为光照不均被分到不同簇。加入空间坐标特征(x,y)并赋予一个合适的权重比如0.3-0.6后分割结果立刻变得连贯多了。这个权重需要根据图像内容调整对于纹理复杂、颜色相近的物体空间权重可以高一些对于颜色区分度大的物体如彩色气球颜色权重可以更高。6. 常见陷阱、问题排查与算法变体即使理解了原理在实际应用FCM时还是会踩不少坑。下面是一些典型问题及解决方案。6.1 初始化敏感性与空簇问题和K-Means一样FCM对初始聚类中心的位置敏感可能收敛到局部最优解。常见的改进策略是多次随机初始化运行算法多次比如10-50次选择目标函数J最小的那次结果作为最终输出。使用更好的初始化方法如K-Means的模糊版本使初始中心点尽可能分散。空簇问题在迭代过程中可能出现某个簇的隶属度对所有样本都趋近于0导致其中心点更新失效出现NaN。这通常发生在初始中心点太差或m值过小的时候。解决方法包括检查并重新初始化出现空簇的这次运行或者采用允许空簇的算法变体但更常见的是通过多次随机初始化来规避。6.2 噪声与异常值处理标准FCM使用欧氏距离的平方这使得它对噪声和异常点非常敏感因为异常点的距离平方会极大从而扭曲聚类中心的位置。为了解决这个问题学者们提出了许多鲁棒的FCM变体FCM with Noise Cluster引入一个“噪声簇”该簇的中心被定义为所有数据的“全局中心”或一个远离数据点的虚拟点。样本到噪声簇的距离是一个固定的值δ。这样远离所有正常簇的异常点会倾向于拥有较高的噪声簇隶属度从而被隔离。Kernel FCM通过核函数如高斯核将数据映射到高维特征空间在高维空间中进行聚类。这可以处理非线性可分的簇结构并且某些核函数对噪声有一定抑制作用。使用其他距离度量比如曼哈顿距离L1距离比欧氏距离L2距离对异常值更不敏感。6.3 算法变体简介除了上述针对噪声的变体FCM家族还有很多成员Gustafson-Kessel (GK) FCM不再假设簇是球形的它为每个簇学习一个局部协方差矩阵从而可以识别椭圆形甚至线性分布的簇。其距离度量变为马氏距离。Gath-Geva (GG) FCM进一步扩展假设每个簇的数据服从高斯分布并估计其概率密度函数。它对于不同大小、密度和形状的簇适应性更强但计算也更复杂。Possibilistic C-Means (PCM)可能性C均值聚类。它放松了“一个样本对所有簇的隶属度和为1”的严格约束允许隶属度表示样本属于一个簇的“典型性”或“可能性”其值可以独立。这使得PCM对噪声和重叠簇更鲁棒但有时会导致多个簇的中心重合。如何选择对于初学者标准FCM是很好的起点。如果数据有明显噪声尝试“带噪声簇的FCM”。如果簇的形状明显是非球形的如椭圆形、拉长的可以尝试GK-FCM。PCM则适用于对噪声极度敏感且不要求隶属度和为1的场景。6.4 性能优化与大数据处理FCM的时间复杂度主要在距离矩阵的计算上是O(C * N * d)其中C是簇数N是样本数d是特征维数。对于大规模数据如图像所有像素直接计算可能很慢。采样如上面的例子可以先在样本上运行FCM得到中心点再为所有数据计算隶属度。使用更快的距离计算库如scipy.spatial.distance.cdist。增量式/在线FCM适用于数据流场景可以逐步更新中心和隶属度。并行化距离计算和隶属度更新都是高度并行的可以利用多核CPU或GPU加速。最后分享一个我踩过的坑在一次处理传感器时间序列数据时我直接用了原始数值做FCM结果聚类完全被几个量纲大的传感器主导。后来对所有特征进行了Z-score标准化聚类结果才真正反映了不同运行模式的区别。数据预处理永远是机器学习建模的第一步也是最关键的一步之一。FCM作为一个强大的工具其效果上限很大程度上取决于你喂给它的数据质量和对问题的理解深度。
返回列表