一种可能的解决方案是使用最近邻方法,可以使用KDTree实现。Scikit-learn提供了一个良好的接口。然后可以使用networkx构建图表示。如果要绘制的线应该通过最近邻,则这只有在最近邻方面真正起作用:
from sklearn.neighbors import KDTree
import numpy as np
import networkx as nx
G = nx.Graph()
X = [(0, 1), (1, 1), (3, 2), (5, 4)]
tree = KDTree(X, leaf_size=2, metric='euclidean')
for p in X
dist, ind = tree.query(p, k=3)
print ind
G.add_node(p)
n1, l1 = X[ind[0][1]], dist[0][1]
n2, l2 = X[ind[0][2]], dist[0][2]
G.add_edge(p, n1)
G.add_edge(p, n2)
print G.edges()
print nx.shortest_path(G, source=(0,1), target=(5,4))
>>> [(0, 1), (1, 1), (3, 2), (5, 4)]
更新:如果起点和终点未知,且数据相对分散,则可以通过查找图中的团来找到端点。起点和终点将形成一个团。如果从团中删除最长的边,则会在图中创建一个自由端点,可用作起点和终点。例如,在此列表中,起点和终点出现在中间位置:
X = [(0, 1), (0, 0), (2, 1), (3, 2), (9, 4), (5, 4)]
![enter image description here](https://istack.dev59.com/iN3Oa.webp)
建立图表后,现在的问题是从团中删除最长的边,以找到图表的自由端点:
def find_longest_edge(l):
e1 = G[l[0]][l[1]]['weight']
e2 = G[l[0]][l[2]]['weight']
e3 = G[l[1]][l[2]]['weight']
if e2 < e1 > e3:
return (l[0], l[1])
elif e1 < e2 > e3:
return (l[0], l[2])
elif e1 < e3 > e2:
return (l[1], l[2])
end_cliques = [i for i in list(nx.find_cliques(G)) if len(i) == 3]
edge_lengths = [find_longest_edge(i) for i in end_cliques]
G.remove_edges_from(edge_lengths)
edges = G.edges()
![enter image description here](https://istack.dev59.com/N9LR3.webp)
start_end = [n for n,nbrs in G.adjacency_iter() if len(nbrs.keys()) == 1]
print nx.shortest_path(G, source=start_end[0], target=start_end[1])
>>> [(0, 0), (0, 1), (2, 1), (3, 2), (5, 4), (9, 4)]