基于模糊 C 均值(Fuzzy C-Means, FCM)聚类
模糊 C 均值(Fuzzy C-Means, FCM) 是一种 软聚类算法,与 KMeans
不同,它允许数据点 部分地属于多个簇,适用于 图像分割、医学诊断、推荐系统等任务。
1. Fuzzy C-Means
vs. KMeans
方法 | 适用情况 | 主要区别 |
---|---|---|
Fuzzy C-Means (FCM) | 适用于模糊分类、软聚类 | 数据点可部分属于多个簇(隶属度) |
KMeans | 适用于硬聚类(每个点只能属于一个簇) | 数据点必须完全属于某个簇 |
示例
- KMeans:每个样本完全属于一个簇。
- FCM:每个样本以一定的 概率(隶属度) 归属于多个簇。
2. Fuzzy C-Means
代码示例
(1) 训练 Fuzzy C-Means
FCM
需要安装 skfuzzy
:
pip install scikit-fuzzy
import numpy as np
import skfuzzy as fuzz
import matplotlib.pyplot as plt
# 生成数据
X = np.random.rand(100, 2).T # 100 个二维点(转置以符合 FCM 格式)
# 训练 FCM 聚类模型
n_clusters = 3
cntr, u, _, _, _, _, _ = fuzz.cmeans(X, c=n_clusters, m=2, error=0.005, maxiter=1000)
# 获取聚类标签
labels = np.argmax(u, axis=0)
print("Fuzzy C-Means 簇标签:", labels[:10])
解释
fuzz.cmeans()
训练Fuzzy C-Means
。c=n_clusters=3
:设定 3 个簇。m=2
:模糊因子,控制数据点的模糊程度(m=1
退化为KMeans
)。u
:隶属度矩阵,表示数据点属于各个簇的概率。labels = np.argmax(u, axis=0)
获取每个数据点最可能的簇标签。
3. Fuzzy C-Means
主要参数
fuzz.cmeans(X, c=3, m=2, error=0.005, maxiter=1000)
参数 | 说明 |
---|---|
X | 数据集(形状: (features, samples) ) |
c | 簇数(类似 KMeans 的 n_clusters ) |
m | 模糊指数(默认 2 ,值越大,聚类越模糊) |
error | 误差阈值(默认 0.005 ,用于收敛判断) |
maxiter | 最大迭代次数(默认 1000 ) |
4. 计算隶属度(Soft Clustering)
print("前 5 个样本的隶属度:\n", u[:, :5])
解释
u[i, j]
表示第j
个样本属于第i
个簇的概率。
5. Fuzzy C-Means
可视化
import seaborn as sns
sns.scatterplot(x=X[0], y=X[1], hue=labels, palette="coolwarm")
plt.scatter(cntr[:, 0], cntr[:, 1], s=200, c="black", marker="X", label="Centroids")
plt.legend()
plt.title("Fuzzy C-Means 聚类结果")
plt.show()
解释
- 黑色
X
标记簇中心。
6. Fuzzy C-Means
vs. KMeans
(软聚类)
from sklearn.cluster import KMeans
# 训练 KMeans
kmeans = KMeans(n_clusters=3, random_state=42)
labels_kmeans = kmeans.fit_predict(X.T)
# 可视化
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].scatter(X[0], X[1], c=labels_kmeans, cmap="coolwarm")
axes[0].set_title("KMeans 硬聚类")
axes[1].scatter(X[0], X[1], c=labels, cmap="coolwarm")
axes[1].set_title("Fuzzy C-Means 软聚类")
plt.show()
解释
KMeans
只能进行硬聚类(数据点只能属于一个簇)。Fuzzy C-Means
允许数据点部分属于多个簇(软聚类)。
7. 计算聚类性能
from sklearn.metrics import silhouette_score
score = silhouette_score(X.T, labels)
print("轮廓系数:", score)
解释
silhouette_score(X.T, labels)
评估聚类效果(值越大越好)。
关于 sklearn
是否支持 FCM
需要注意的是,scikit-learn
并未内置 FCM 算法的支持。其主要提供硬聚类方法(如 K-Means),而 FCM 属于软聚类范畴。如果希望使用 sklearn
中的功能扩展到 FCM,则需自行实现或借助第三方库完成。
然而,可以通过继承 BaseEstimator
和 ClusterMixin
类来自定义一个类似的接口封装 skfuzzy
的 FCM 功能。下面是一个简单的自定义封装例子:
from sklearn.base import BaseEstimator, ClusterMixin
import skfuzzy as fuzz
class FuzzyCMeans(BaseEstimator, ClusterMixin):
def __init__(self, n_clusters=2, m=2, error=0.005, max_iter=1000):
self.n_clusters = n_clusters
self.m = m
self.error = error
self.max_iter = max_iter
def fit(self, X):
self.centers_, self.u_, _, _, _, _, _ = fuzz.cluster.cmeans(
X.T, self.n_clusters, self.m, error=self.error, maxiter=self.max_iter, init=None
)
return self
def predict(self, X):
_, u_predict, _, _, _, _ = fuzz.cluster.cmeans_predict(
X.T, self.centers_, self.m, error=self.error, maxiter=self.max_iter
)
return np.argmax(u_predict, axis=0)
# 示例调用
model = FuzzyCMeans(n_clusters=3, m=2, error=0.005, max_iter=1000)
model.fit(data.T)
predictions = model.predict(data.T)
print(predictions[:10])
此封装允许用户像操作其他 sklearn
模型一样使用 FCM 方法。
8. 适用场景
- 医学诊断(如病人可能属于多个疾病类别)。
- 推荐系统(如用户可能对多个类别有兴趣)。
- 图像分割(如边界区域的像素可以部分属于多个区域)。
9. 结论
Fuzzy C-Means
适用于软聚类任务,每个数据点可以部分属于多个簇,适用于医学、推荐系统、图像分割,相比KMeans
更灵活但计算复杂度更高。