本文目录导读:

我来详细讲解如何使用Scikit-learn进行连通分量分析,连通分量分析常用于图像处理、图论分析等领域。
数据集准备
1 创建示例数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.neighbors import kneighbors_graph
from sklearn.manifold import spectral_embedding
from sklearn import datasets
# 生成示例数据集(月亮形状数据)
X, y = datasets.make_moons(n_samples=200, noise=0.05, random_state=42)
# 可视化原始数据
plt.figure(figsize=(8, 6))
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='viridis')'原始数据分布')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.show()
基于DBSCAN的连通分量分析
1 DBSCAN实现连通分量
# 使用DBSCAN进行聚类,eps控制邻域大小
dbscan = DBSCAN(eps=0.2, min_samples=5)
clusters = dbscan.fit_predict(X)
# 可视化连通分量
plt.figure(figsize=(10, 6))
unique_clusters = np.unique(clusters)
# 为不同分量着色
colors = ['blue', 'red', 'green', 'purple', 'orange', 'brown']
for i, cluster_id in enumerate(unique_clusters):
mask = clusters == cluster_id
if cluster_id == -1: # 噪声点
plt.scatter(X[mask, 0], X[mask, 1], c='gray',
label='噪声', alpha=0.5, marker='x')
else:
plt.scatter(X[mask, 0], X[mask, 1], c=colors[i % len(colors)],
label=f'分量 {cluster_id}')
'DBSCAN连通分量分析')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.legend()
plt.show()
print(f"找到的连通分量数量(不包括噪声): {len(unique_clusters[unique_clusters != -1])}")
基于最近邻图的连通分量
1 构建k近邻图
from scipy.sparse.csgraph import connected_components
from sklearn.neighbors import NearestNeighbors
# 构建k近邻图
k = 5
nn = NearestNeighbors(n_neighbors=k)
nn.fit(X)
knn_graph = nn.kneighbors_graph(X, mode='distance')
# 计算连通分量
n_components, labels = connected_components(csgraph=knn_graph, directed=False, return_labels=True)
print(f"k近邻图中的连通分量数量: {n_components}")
# 可视化连通分量
plt.figure(figsize=(10, 6))
colors = plt.cm.Set1(np.linspace(0, 1, n_components))
for i in range(n_components):
mask = labels == i
plt.scatter(X[mask, 0], X[mask, 1], c=[colors[i]],
label=f'分量 {i}', alpha=0.7)
f'基于k近邻图(K={k})的连通分量')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.legend()
plt.show()
基于谱聚类的连通分量
1 谱聚类实现
from sklearn.cluster import SpectralClustering
# 谱聚类
n_components_spectral = 2
spectral = SpectralClustering(n_clusters=n_components_spectral,
affinity='nearest_neighbors',
random_state=42)
spectral_labels = spectral.fit_predict(X)
# 可视化谱聚类结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=spectral_labels, cmap='viridis')'谱聚类连通分量分析')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.colorbar(label='分量标签')
plt.show()
高级应用:层次连通分量分析
1 层次聚类实现
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram
# 层次聚类
hierarchical = AgglomerativeClustering(n_clusters=None,
distance_threshold=0.3,
linkage='ward')
hierarchical_labels = hierarchical.fit_predict(X)
# 可视化层次聚类结果
plt.figure(figsize=(10, 6))
unique_labels = np.unique(hierarchical_labels)
colors = plt.cm.tab20(np.linspace(0, 1, len(unique_labels)))
for i, label in enumerate(unique_labels):
mask = hierarchical_labels == label
plt.scatter(X[mask, 0], X[mask, 1], c=[colors[i]],
label=f'分量 {label}', alpha=0.7)
'层次聚类连通分量分析')
plt.xlabel('特征1')
plt.ylabel('特征2')
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
实际应用案例:图像分割
1 图像连通分量分析
from sklearn.feature_extraction import image
from sklearn.cluster import KMeans
# 创建模拟图像数据
np.random.seed(42)
image_shape = (50, 50)
image_data = np.random.rand(*image_shape)
# 添加一些结构化的区域
image_data[10:20, 10:20] = 0.8
image_data[30:40, 30:40] = 0.2
image_data[5:15, 35:45] = 0.6
# 转换为特征矩阵
X_img = image_data.reshape(-1, 1)
# 使用KMeans进行图像分割
kmeans = KMeans(n_clusters=3, random_state=42)
labels_img = kmeans.fit_predict(X_img)
labels_img_2d = labels_img.reshape(image_shape)
# 可视化
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].imshow(image_data, cmap='gray')
axes[0].set_title('原始图像')
axes[1].imshow(labels_img_2d, cmap='viridis')
axes[1].set_title('连通分量分割结果')
plt.tight_layout()
plt.show()
性能评估与优化
1 评估不同方法的性能
import time
from sklearn.metrics import silhouette_score
# 定义测试方法
methods = {
'DBSCAN': {'estimator': DBSCAN(eps=0.2, min_samples=5), 'params': {}},
'Spectral': {'estimator': SpectralClustering(n_clusters=2, random_state=42), 'params': {}},
'Hierarchical': {'estimator': AgglomerativeClustering(n_clusters=2), 'params': {}}
}
results = []
for method_name, method_dict in methods.items():
start_time = time.time()
# 拟合模型
labels_pred = method_dict['estimator'].fit_predict(X)
# 计算时间
elapsed_time = time.time() - start_time
# 计算轮廓系数(如果有多个分量)
if len(np.unique(labels_pred)) > 1:
silhouette = silhouette_score(X, labels_pred)
else:
silhouette = None
results.append({
'method': method_name,
'time': elapsed_time,
'silhouette_score': silhouette,
'n_components': len(np.unique(labels_pred))
})
# 显示结果
results_df = pd.DataFrame(results)
print("性能比较:")
print(results_df)
实际应用:社交网络分析
1 网络图的连通分量
from sklearn.neighbors import radius_neighbors_graph
# 模拟社交网络数据
np.random.seed(42)
n_users = 100
user_features = np.random.randn(n_users, 5)
# 构建基于半径的邻接图
radius = 2.5
adjacency_graph = radius_neighbors_graph(user_features, radius=radius)
# 计算连通分量
n_components_network, component_labels = connected_components(
csgraph=adjacency_graph, directed=False, return_labels=True
)
# 统计分量大小
component_sizes = pd.Series(component_labels).value_counts().sort_index()
print(f"社交网络中的连通分量数量: {n_components_network}")
print("\n各分量大小:")
print(component_sizes.head(10))
# 可视化分量分布
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
component_sizes.plot(kind='bar', color='skyblue')'各连通分量大小分布')
plt.xlabel('分量编号')
plt.ylabel('节点数量')
plt.subplot(1, 2, 2)
plt.hist(component_sizes, bins=20, color='lightgreen', edgecolor='black')'分量大小直方图')
plt.xlabel('分量大小')
plt.ylabel('频率')
plt.tight_layout()
plt.show()
Scikit-learn提供了多种实现连通分量分析的方法:
- DBSCAN:基于密度的聚类,适合发现任意形状的分量
- k近邻图:通过图论方法找到连接的子图
- 谱聚类:基于图拉普拉斯矩阵的谱分解
- 层次聚类:通过层次化方法发现不同粒度的分量
选择哪种方法取决于你的具体需求:
- 数据量大小
- 分量形状(凸形/非凸形)
- 噪声处理要求
- 计算资源限制
在实际应用中,建议尝试多种方法并进行比较,选择最适合数据特征的方法。