Pandas 在数据帧中查找城市之间的最短值
我有一个数据框,上面有城市和每个城市之间的距离。我的数据集看起来像 df 我计划参观所有的城市,我试图找出我能以最短距离旅行的城市顺序。我想以一个起始位置结束。起点和终点应该相同Pandas 在数据帧中查找城市之间的最短值,pandas,networkx,dijkstra,shortest-path,Pandas,Networkx,Dijkstra,Shortest Path,我有一个数据框,上面有城市和每个城市之间的距离。我的数据集看起来像 df 我计划参观所有的城市,我试图找出我能以最短距离旅行的城市顺序。我想以一个起始位置结束。起点和终点应该相同 有没有办法找到跨越所有城市的最短距离,或者有任何其他方法可用。请帮忙。迟交答案。我一直面临着同样的问题。留下一个解决方案,以防有人需要它来解决TSP和绘制结果图 import numpy as np import pandas as pd from tsp_solver.greedy import solve_tsp
有没有办法找到跨越所有城市的最短距离,或者有任何其他方法可用。请帮忙。迟交答案。我一直面临着同样的问题。留下一个解决方案,以防有人需要它来解决TSP和绘制结果图
import numpy as np
import pandas as pd
from tsp_solver.greedy import solve_tsp
from tsp_solver.util import path_cost
import matplotlib.pyplot as plt
import seaborn as sns
import networkx as nx
# for Jupyter Notebook
from IPython.display import Image
定义距离矩阵数据帧
# Define distances matrix dataframe
df = pd.DataFrame({
'A': [np.nan, 2166, 577, 175],
'B': [2166, np.nan, 1806, 2092],
'C': [577, 1806, np.nan, 653],
'D': [175, 2092, 653, np.nan]
}, index=['A', 'B', 'C', 'D'])
print(df)
A B C D
A NaN 2166.0 577.0 175.0
B 2166.0 NaN 1806.0 2092.0
C 577.0 1806.0 NaN 653.0
D 175.0 2092.0 653.0 NaN
填补空缺
取下幂零三角矩阵平方对称距离矩阵
# Take the lower nilpotent triangular matrix
lower_nilpotent_triangular_df = pd.DataFrame(
np.tril(df),
columns=df.columns,
index=df.index
)
print(lower_nilpotent_triangular_df)
A B C D
A 0.0 0.0 0.0 0.0
B 2166.0 0.0 0.0 0.0
C 577.0 1806.0 0.0 0.0
D 175.0 2092.0 653.0 0.0
求解循环旅行商问题
# Solve the circular shortest path
# NOTE: since it is circular, endpoints=(0,0)
# is equal to endpoints=(1,1) etc...
path = solve_tsp(lower_nilpotent_triangular_df.to_numpy(), endpoints=(0, 0))
path_len = path_cost(lower_nilpotent_triangular_df.to_numpy(), path)
# Take path labels from df
path_labels = df.columns[path].to_numpy()
print('shortest circular path:', path_labels)
print('path length:', path_len)
shortest circular path: ['A' 'D' 'B' 'C' 'A']
path length: 4650.0
用最短路径绘制图形
# Define graph edges widths
shortest_path_widths = df.copy(deep=True)
shortest_path_widths.loc[:,:] = .25
for idx0, idx1 in zip(path_labels[:-1], path_labels[1:]):
shortest_path_widths.loc[idx0, idx1] = 4.
shortest_path_widths.loc[idx1, idx0] = 4.
我强烈建议您研究一下:您的问题是有效地解决TSP问题。实际上,任何使用邻接矩阵作为输入的解算器都应该可以工作。我不确定cdist是否是一个好答案@Dark,因为旅行推销员是一个NP难问题。您可能需要安装tsp解算器,然后使用pd.Seriestsp_solver.greedy.solve_tspdf.fillna0.values.replacedictenumeratedf.columns。希望如此helps@pyd首先用nan或零替换所有缺少的值。然后使用上面的代码。当您处理数字时,数据框中不会有任何对象数据类型。
# mask
mask = np.zeros_like(lower_nilpotent_triangular_df)
mask[np.triu_indices_from(mask)] = True
# plot the matrix
sns.heatmap(lower_nilpotent_triangular_df,
annot=True, fmt='.0f',
cmap="YlGnBu", mask=mask)
plt.show()
# Solve the circular shortest path
# NOTE: since it is circular, endpoints=(0,0)
# is equal to endpoints=(1,1) etc...
path = solve_tsp(lower_nilpotent_triangular_df.to_numpy(), endpoints=(0, 0))
path_len = path_cost(lower_nilpotent_triangular_df.to_numpy(), path)
# Take path labels from df
path_labels = df.columns[path].to_numpy()
print('shortest circular path:', path_labels)
print('path length:', path_len)
shortest circular path: ['A' 'D' 'B' 'C' 'A']
path length: 4650.0
# Define graph edges widths
shortest_path_widths = df.copy(deep=True)
shortest_path_widths.loc[:,:] = .25
for idx0, idx1 in zip(path_labels[:-1], path_labels[1:]):
shortest_path_widths.loc[idx0, idx1] = 4.
shortest_path_widths.loc[idx1, idx0] = 4.
# Show the graph
G = nx.DiGraph()
for r in lower_nilpotent_triangular_df.columns:
for c in lower_nilpotent_triangular_df.index:
if not lower_nilpotent_triangular_df.loc[r, c]:
continue
G.add_edge(
r, c,
# scaled edge length
length=lower_nilpotent_triangular_df.loc[r, c]/250,
# edge label
label=int(lower_nilpotent_triangular_df.loc[r, c]),
# no direction
dir='none',
# edge width
penwidth=shortest_path_widths.loc[r, c]
)
# Add attributes
for u,v,d in G.edges(data=True):
d['label'] = d.get('label','')
d['len'] = d.get('length','')
d['penwidth'] = d.get('penwidth','')
A = nx.nx_agraph.to_agraph(G)
A.node_attr.update(color="skyblue", style="filled",
shape='circle', height=.4,
fixedsize=True)
A.edge_attr.update(color="black", fontsize=10)
A.draw('cities.png', format='png', prog='neato')
# Show image in Jupyter Notebook
Image('cities.png')