本文目录导读:

我来介绍如何使用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中创建最近邻图的各种方法,包括:
- 基本的k近邻图和半径图
- 不同k值对图结构的影响
- 不同的距离度量
- 实际应用(聚类、图像分割)
- 性能优化(处理大型数据集)
- 自定义权重函数
最近邻图在机器学习中广泛应用,如谱聚类、半监督学习、流形学习等任务中都非常重要。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播