【问题标题】:Finding shortest values between the cities in a dataframe在数据框中查找城市之间的最短值
【发布时间】:2018-10-16 05:12:37
【问题描述】:

我有一个数据框,其中包含城市以及每个城市的其他城市之间的距离。我的数据集看起来像,

df,

 From City      City A  City B City C  City D
 City A                 2166    577     175
 City B         2166            1806    2092
 City C         577     1806            653
 City D         175     2092    653 

我计划访问所有城市,我正在尝试找出我可以以最短距离旅行的城市顺序。我想以一个起始位置结束。 起点和终点应该相同。

有没有办法找到跨所有城市的最短距离,或者任何其他方法都可用。请帮忙。

【问题讨论】:

  • 我强烈建议您调查一下:github.com/dmishin/tsp-solver
  • 您的问题正在有效地解决 TSP。
  • 从字面上看,任何使用邻接矩阵作为输入的求解器都应该可以工作。我不确定 cdist 是一个很好的答案@Dark,因为旅行推销员是一个 NP 难题。
  • 您可能需要安装 tsp-solver 然后使用pd.Series(tsp_solver.greedy.solve_tsp(df.fillna(0).values)).replace(dict(enumerate(df.columns)))。希望对你有帮助
  • @pyd 首先将所有缺失值替换为 nan 或零。然后使用上面的代码。当您处理数字时,数据框中不应有任何对象 dtype。

标签: pandas networkx dijkstra shortest-path


【解决方案1】:

迟到的答案。我一直面临着同样的问题。使用tsp_solver 解决 TSP 和networkxpygraphviz 来绘制结果图,留下解决方案(以防有人需要)。

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

定义距离矩阵DataFrame

# 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

填写NaNs

# Fill NaNs with 0s
df.fillna(0, inplace=True)
# plot the matrix
sns.heatmap(df, annot=True, fmt='.0f', cmap="YlGnBu")
plt.show()

取下幂零三角矩阵(平方对称距离矩阵)

# 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
# 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')

【讨论】:

    猜你喜欢
    • 2021-09-11
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多