Python案例如何用Scikit-learn做最近邻图

wen python案例 1

本文目录导读:

Python案例如何用Scikit-learn做最近邻图

  1. 基础最近邻图
  2. 不同k值的影响
  3. 半径最近邻图
  4. 使用不同距离度量
  5. 实际应用:图聚类
  6. 高效处理大型数据集
  7. 自定义权重函数
  8. 可视化最近邻关系
  9. 实际应用:图像分割

我来介绍如何使用Scikit-learn创建最近邻图的几种方法。

基础最近邻图

import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import kneighbors_graph
from sklearn.datasets import make_blobs
# 创建示例数据
X, _ = make_blobs(n_samples=30, centers=3, n_features=2, random_state=42)
# 创建k最近邻图 (k=3)
k = 3
A = kneighbors_graph(X, k, mode='connectivity', include_self=False)
# 或使用距离度量
A_dist = kneighbors_graph(X, k, mode='distance', include_self=False)
# 可视化
plt.figure(figsize=(12, 4))
plt.subplot(131)
plt.scatter(X[:, 0], X[:, 1], alpha=0.7)'原始数据点')
plt.subplot(132)
plt.spy(A.toarray(), markersize=5)f'KNN邻接矩阵 (k={k})')
plt.subplot(133)
# 绘制连接图
A_array = A.toarray()
for i in range(len(X)):
    for j in range(len(X)):
        if A_array[i, j] > 0:
            plt.plot([X[i, 0], X[j, 0]], [X[i, 1], X[j, 1]], 'gray', alpha=0.5)
plt.scatter(X[:, 0], X[:, 1], alpha=0.7)f'KNN图 (k={k})')
plt.tight_layout()
plt.show()
print(f"邻接矩阵形状: {A.shape}")
print(f"非零元素数量: {A.nnz}")
print(f"稀疏度: {A.nnz / (A.shape[0] * A.shape[1]):.3f}")

不同k值的影响

# 对比不同k值的最近邻图
k_values = [1, 3, 5, 10]
fig, axes = plt.subplots(1, 4, figsize=(16, 4))
for idx, k in enumerate(k_values):
    A = kneighbors_graph(X, k, mode='connectivity', include_self=False)
    # 绘制连接图
    A_array = A.toarray()
    for i in range(len(X)):
        for j in range(len(X)):
            if A_array[i, j] > 0:
                axes[idx].plot([X[i, 0], X[j, 0]], [X[i, 1], X[j, 1]], 'gray', alpha=0.3)
    axes[idx].scatter(X[:, 0], X[:, 1], alpha=0.7)
    axes[idx].set_title(f'k={k}')
    axes[idx].set_xlabel('X1')
    axes[idx].set_ylabel('X2')
plt.tight_layout()
plt.show()

半径最近邻图

from sklearn.neighbors import radius_neighbors_graph
# 创建半径最近邻图
radius = 2.0
A_radius = radius_neighbors_graph(X, radius, mode='connectivity', include_self=False)
# 可视化
plt.figure(figsize=(12, 4))
plt.subplot(121)
A_array = A_radius.toarray()
for i in range(len(X)):
    for j in range(len(X)):
        if A_array[i, j] > 0:
            plt.plot([X[i, 0], X[j, 0]], [X[i, 1], X[j, 1]], 'gray', alpha=0.5)
plt.scatter(X[:, 0], X[:, 1], alpha=0.7)f'半径最近邻图 (radius={radius})')
plt.subplot(122)
plt.spy(A_radius.toarray(), markersize=5)'邻接矩阵')
plt.tight_layout()
plt.show()
print(f"半径图非零连接数: {A_radius.nnz}")

使用不同距离度量

from sklearn.neighbors import NearestNeighbors
# 不同的距离度量
metrics = ['euclidean', 'manhattan', 'cosine', 'minkowski']
k = 3
fig, axes = plt.subplots(2, 2, figsize=(12, 12))
for idx, metric in enumerate(metrics):
    row = idx // 2
    col = idx % 2
    # 使用NearestNeighbors
    nn = NearestNeighbors(n_neighbors=k, metric=metric)
    nn.fit(X)
    A = kneighbors_graph(X, k, mode='connectivity', metric=metric)
    # 绘制
    A_array = A.toarray()
    for i in range(len(X)):
        for j in range(len(X)):
            if A_array[i, j] > 0:
                axes[row, col].plot([X[i, 0], X[j, 0]], [X[i, 1], X[j, 1]], 'gray', alpha=0.3)
    axes[row, col].scatter(X[:, 0], X[:, 1], alpha=0.7)
    axes[row, col].set_title(f'度量: {metric}')
    axes[row, col].set_xlabel('X1')
    axes[row, col].set_ylabel('X2')
plt.tight_layout()
plt.show()

实际应用:图聚类

from sklearn.cluster import SpectralClustering
from sklearn.neighbors import kneighbors_graph
from sklearn.metrics import adjusted_rand_score
from sklearn.datasets import make_circles
# 创建环形数据
X_circles, y_circles = make_circles(n_samples=200, noise=0.05, factor=0.5)
# 使用k近邻图进行谱聚类
k_values = [2, 5, 10, 20]
fig, axes = plt.subplots(2, 2, figsize=(10, 10))
for idx, k in enumerate(k_values):
    row = idx // 2
    col = idx % 2
    # 创建k近邻图
    A = kneighbors_graph(X_circles, k, mode='connectivity')
    # 谱聚类
    sc = SpectralClustering(n_clusters=2, affinity='precomputed', random_state=42)
    labels = sc.fit_predict(A)
    # 计算ARI
    ari = adjusted_rand_score(y_circles, labels)
    axes[row, col].scatter(X_circles[:, 0], X_circles[:, 1], c=labels, 
                          cmap='viridis', alpha=0.7)
    axes[row, col].set_title(f'k={k}, ARI={ari:.3f}')
    axes[row, col].set_xlabel('X1')
    axes[row, col].set_ylabel('X2')
plt.tight_layout()
plt.show()

高效处理大型数据集

import time
from sklearn.datasets import make_classification
# 创建大型数据集
n_samples = 1000
X_large, _ = make_classification(n_samples=n_samples, n_features=10)
# 比较不同的算法
from sklearn.neighbors import NearestNeighbors
k = 5
methods = ['auto', 'ball_tree', 'kd_tree', 'brute']
for method in methods:
    start_time = time.time()
    # 使用NearestNeighbors
    nn = NearestNeighbors(n_neighbors=k, algorithm=method)
    nn.fit(X_large)
    graph = kneighbors_graph(X_large, k, mode='connectivity', 
                             algorithm=method, n_jobs=-1)
    elapsed_time = time.time() - start_time
    print(f"{method}: {elapsed_time:.4f} 秒")
print(f"图形形状: {graph.shape}")
print(f"稀疏度: {graph.nnz / (n_samples * n_samples):.6f}")

自定义权重函数

# 创建加权最近邻图
def gaussian_kernel(distances, sigma=1.0):
    """高斯核权重函数"""
    return np.exp(-distances ** 2 / (2 * sigma ** 2))
def inverse_distance(distances, power=2):
    """逆距离权重函数"""
    return 1.0 / (distances ** power + 1e-10)
# 创建加权图
k = 5
X_sample = X[:20]  # 使用前20个点
# 获取距离矩阵
nn = NearestNeighbors(n_neighbors=k, metric='euclidean')
nn.fit(X_sample)
distances, indices = nn.kneighbors(X_sample, return_distance=True)
# 应用不同的权重
weights_gaussian = gaussian_kernel(distances, sigma=1.0)
weights_inverse = inverse_distance(distances, power=2)
print("高斯权重:")
print(weights_gaussian[:3])
print("\n逆距离权重:")
print(weights_inverse[:3])

可视化最近邻关系

# 详细的可视化一个点的最近邻
def plot_knn_details(X, point_idx, k=5):
    """可视化特定点的最近邻"""
    nn = NearestNeighbors(n_neighbors=k+1)  # +1 because self is included
    nn.fit(X)
    distances, indices = nn.kneighbors(X[point_idx].reshape(1, -1))
    neighbors = indices[0][1:]  # 排除自身
    plt.figure(figsize=(10, 8))
    # 绘制所有点
    plt.scatter(X[:, 0], X[:, 1], alpha=0.5, label='其他点')
    # 高亮目标点
    plt.scatter(X[point_idx, 0], X[point_idx, 1], 
                color='red', s=100, label='目标点', zorder=5)
    # 高亮k个最近邻
    plt.scatter(X[neighbors, 0], X[neighbors, 1], 
                color='green', s=100, label=f'k}个邻居', zorder=5)
    # 画连接线
    for neighbor_idx in neighbors:
        plt.plot([X[point_idx, 0], X[neighbor_idx, 0]], 
                [X[point_idx, 1], X[neighbor_idx, 1]], 
                'gray', alpha=0.5, linestyle='--')
    plt.legend()
    plt.title(f'点 {point_idx} 的最近{k}个邻居')
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.grid(True, alpha=0.3)
    plt.show()
    print(f"目标点: {X[point_idx]}")
    print(f"k}个邻居索引: {neighbors}")
    print(f"k}个邻居距离: {distances[0][1:]}")
# 使用
plot_knn_details(X, point_idx=10, k=5)

实际应用:图像分割

from sklearn.feature_extraction.image import img_to_graph
from sklearn.cluster import spectral_clustering
import matplotlib.image as mpimg
# 创建一个简单的合成图像
np.random.seed(42)
img_size = 20
img = np.zeros((img_size, img_size, 3))
img[5:15, 5:15] = [0.8, 0.2, 0.2]  # 红色矩形
img[7:13, 7:13] = [0.2, 0.8, 0.2]  # 绿色小矩形
# 添加噪声
img += np.random.randn(*img.shape) * 0.05
# 使用最近邻图进行图像分割
graph = img_to_graph(img, mask=None)
# 使用k近邻图
k = 10
A_knn = kneighbors_graph(graph, k, mode='connectivity')
# 谱聚类
labels = spectral_clustering(A_knn, n_clusters=3, random_state=42)
labels_img = labels.reshape(img_size, img_size)
# 可视化
plt.figure(figsize=(12, 4))
plt.subplot(131)
plt.imshow(img)'原始图像')
plt.axis('off')
plt.subplot(132)
plt.spy(A_knn[:100, :100].toarray(), markersize=1)'KNN图(前100个像素)')
plt.subplot(133)
plt.imshow(labels_img, cmap='viridis')'KNN谱聚类结果')
plt.axis('off')
plt.tight_layout()
plt.show()

这些示例展示了Scikit-learn中创建最近邻图的各种方法,包括:

  1. 基本的k近邻图和半径图
  2. 不同k值对图结构的影响
  3. 不同的距离度量
  4. 实际应用(聚类、图像分割)
  5. 性能优化(处理大型数据集)
  6. 自定义权重函数

最近邻图在机器学习中广泛应用,如谱聚类、半监督学习、流形学习等任务中都非常重要。

抱歉,评论功能暂时关闭!