Python实战:用sklearn实现FCM模糊聚类(附完整代码与数据集)

在数据科学领域,聚类分析是最基础也最常用的技术之一。不同于传统的硬聚类方法(如K-means)要求每个数据点只能属于一个类别,模糊C均值聚类(FCM)允许数据点以不同隶属度属于多个类别,这种"软分配"特性使其在处理边界模糊的数据时表现尤为出色。本文将手把手教你如何用Python的sklearn生态系统实现FCM算法,从数据预处理到结果可视化全流程覆盖,特别适合已经掌握基础机器学习概念、想要进阶实践的数据从业者。

1. 环境准备与数据加载

1.1 安装必要库

虽然scikit-learn没有原生实现FCM,但可以通过sklearn-fuzzy扩展库轻松实现。首先确保已安装以下依赖:

pip install scikit-learn numpy matplotlib scikit-fuzzy pandas

注意:如果使用Jupyter Notebook,建议在单元格开头添加%matplotlib inline以显示图表。

1.2 数据集选择与加载

我们使用经典的鸢尾花数据集作为演示,该数据集包含150个样本,每个样本有4个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度):

from sklearn import datasets
import pandas as pd

iris = datasets.load_iris()
X = iris.data
feature_names = iris.feature_names
df = pd.DataFrame(X, columns=feature_names)

查看数据前五行:

花萼长度 (cm) 花萼宽度 (cm) 花瓣长度 (cm) 花瓣宽度 (cm)
5.1 3.5 1.4 0.2
4.9 3.0 1.4 0.2
4.7 3.2 1.3 0.2
4.6 3.1 1.5 0.2
5.0 3.6 1.4 0.2

2. FCM算法核心实现

2.1 模型初始化与参数解释

使用sklearn-fuzzycmeans函数实现FCM:

import skfuzzy as fuzz

# 定义关键参数
n_clusters = 3      # 聚类数量
m = 2.0             # 模糊因子(通常1.1-2.5)
max_iter = 100      # 最大迭代次数
error = 1e-5        # 停止阈值

# 转置数据以满足函数输入要求
data = X.T

参数说明:

  • 模糊因子m:控制聚类模糊程度,m=1退化为K-means,m越大隶属度越分散
  • 停止条件:当隶属度矩阵变化小于error或达到max_iter时终止

2.2 训练模型与结果提取

执行聚类并获取关键输出:

cntr, u, u0, d, jm, p, fpc = fuzz.cluster.cmeans(
    data, n_clusters, m, error, max_iter
)

# 获取每个样本的隶属度
cluster_membership = np.argmax(u, axis=0)

关键输出变量:

  • cntr:最终聚类中心坐标(3×4矩阵)
  • u:隶属度矩阵(3×150矩阵)
  • fpc:模糊划分系数(0-1,值越大聚类效果越好)

3. 结果分析与可视化

3.1 聚类效果评估

计算并打印关键指标:

print(f"模糊划分系数(FPC): {fpc:.3f}")
print("聚类中心坐标:")
for i, center in enumerate(cntr):
    print(f"Cluster {i}: {center}")

典型输出示例:

模糊划分系数(FPC): 0.892
聚类中心坐标:
Cluster 0: [5.88 2.74 4.36 1.39]
Cluster 1: [6.85 3.07 5.74 2.07]
Cluster 2: [5.00 3.42 1.46 0.24]

3.2 多维数据可视化

由于原始数据是四维的,我们选择前两个主成分进行可视化:

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

# 降维到2D
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)

# 绘制聚类结果
fig, ax = plt.subplots(figsize=(10,6))
for i in range(n_clusters):
    ax.scatter(
        X_pca[cluster_membership==i, 0], 
        X_pca[cluster_membership==i, 1],
        label=f'Cluster {i}',
        alpha=0.7
    )
    
# 标记聚类中心
centers_pca = pca.transform(cntr)
ax.scatter(
    centers_pca[:,0], centers_pca[:,1],
    marker='X', s=200, c='black',
    label='Cluster Centers'
)

ax.set_title('FCM聚类结果(PCA降维)')
ax.legend()
plt.show()

FCM聚类可视化示例
图:鸢尾花数据集的FCM聚类结果(不同颜色代表不同簇,X标记为聚类中心)

4. 高级技巧与实战建议

4.1 确定最佳聚类数

使用肘部法则结合模糊划分系数选择最优聚类数:

fpc_scores = []
cluster_range = range(2,6)

for n in cluster_range:
    _, _, _, _, _, _, fpc = fuzz.cluster.cmeans(
        data, n, m, error, max_iter
    )
    fpc_scores.append(fpc)

# 绘制FPC曲线
plt.plot(cluster_range, fpc_scores, 'o-')
plt.xlabel('Number of clusters')
plt.ylabel('Fuzzy Partition Coefficient')
plt.title('FPC vs Cluster Number')

4.2 处理高维数据的实用技巧

当特征维度较高时(>50维),建议:

  1. 先使用PCA/TSNE进行降维
  2. 对特征进行标准化处理
  3. 调整模糊因子m的值(通常1.5-2.0效果较好)
from sklearn.preprocessing import StandardScaler

# 标准化数据
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 重新训练模型
data_scaled = X_scaled.T
cntr_scaled, u_scaled, *_ = fuzz.cluster.cmeans(
    data_scaled, n_clusters, m, error, max_iter
)

4.3 常见问题排查

问题1:聚类结果不稳定

  • 解决方案:增加max_iter或减小error阈值,多次运行取最优

问题2:FPC值过低(<0.5)

  • 检查数据是否适合聚类(计算轮廓系数)
  • 尝试不同的模糊因子m值
  • 考虑数据本身可能没有明显簇结构

问题3:运行速度慢

  • 对大数据集使用Mini-Batch FCM变种
  • 先使用K-means初始化聚类中心
# 使用K-means初始化中心
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3).fit(X)
initial_centers = kmeans.cluster_centers_.T

5. 完整代码示例

以下是整合所有步骤的完整可执行代码:

# 完整FCM实现示例
import numpy as np
import pandas as pd
import skfuzzy as fuzz
from sklearn import datasets
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

# 1. 数据准备
iris = datasets.load_iris()
X = iris.data
data = X.T

# 2. 参数设置
n_clusters = 3
m = 2.0
max_iter = 100
error = 1e-5

# 3. 训练FCM模型
cntr, u, *_ = fuzz.cluster.cmeans(
    data, n_clusters, m, error, max_iter
)

# 4. 结果处理
cluster_membership = np.argmax(u, axis=0)
print(f"模糊划分系数: {fuzz.cluster.cmeans_predict(data, cntr, m)[1]:.3f}")

# 5. 可视化
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
plt.figure(figsize=(10,6))
for i in range(n_clusters):
    plt.scatter(
        X_pca[cluster_membership==i, 0],
        X_pca[cluster_membership==i, 1],
        label=f'Cluster {i}'
    )
centers_pca = pca.transform(cntr.T)
plt.scatter(
    centers_pca[:,0], centers_pca[:,1],
    marker='X', s=200, c='black',
    label='Centers'
)
plt.legend()
plt.title('FCM Clustering Result')
plt.show()
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐