Python 我想将节点和距离矩阵转换为一个表,其中包含节点1、节点2的列以及它们之间的距离

Python 我想将节点和距离矩阵转换为一个表,其中包含节点1、节点2的列以及它们之间的距离,python,pandas,numpy,networkx,Python,Pandas,Numpy,Networkx,我正在使用csv文件,该文件包含每个节点的标题和每个节点的对应行,每个数据字段对应两个节点之间的差异,如下所示: 空白 4. 38 71 90 94 ... 8545 4. 0 1280 1762 1406 1589 ... 1017 38 1280 0 681 202 385 ... 1433 71 1762 681 0 503 0 ... 0 90 1406 202 503 0 0 ... 1559 94 1589 385 0 0 0 ... 1742 .. .. ... ... ... .

我正在使用csv文件,该文件包含每个节点的标题和每个节点的对应行,每个数据字段对应两个节点之间的差异,如下所示:

空白 4. 38 71 90 94 ... 8545 4. 0 1280 1762 1406 1589 ... 1017 38 1280 0 681 202 385 ... 1433 71 1762 681 0 503 0 ... 0 90 1406 202 503 0 0 ... 1559 94 1589 385 0 0 0 ... 1742 .. .. ... ... ... ... 0 ... 8545 1017 1433 0 1559 1742 ... 0
我想用的是熊猫

A只是有一些或多或少相似的随机数据

现在,我们使用

df = pd.DataFrame(A, columns = [ "node_" + str(i) for i in range(A.shape[0])])
您可以
df.stack()

您可以将其设置为带有pd的数据帧。数据帧(df_堆叠)

使用此处可获得更好的性能,如带有列表理解的pd.concat:

df2 = df.stack().rename_axis(['Node1','Node2']).reset_index(name='Distance')
print (df2.head(15))
    Node1 Node2  Distance
0       4     4         0
1       4    38      1280
2       4    71      1762
3       4    90      1406
4       4    94      1589
5       4  8545      1017
6      38     4      1280
7      38    38         0
8      38    71       681
9      38    90       202
10     38    94       385
11     38  8545      1433
12     71     4      1762
13     71    38       681
14     71    71         0
另一个想法是使用numpy:

c = np.tile(df.columns, len(df))
i = np.repeat(df.index, len(df.columns))
v = np.ravel(df)

df2 = pd.DataFrame({'Node1':i, 'Node2':c, 'Distance':v})
性能

#6k rows
df = pd.concat([df] * 1000, ignore_index=True)
# print(df)

In [37]: %timeit df2 = pd.DataFrame({'Node1':np.repeat(df.index, len(df.columns)), 'Node2':np.tile(df.columns, len(df)), 'Distance':np.ravel(df)})
1.77 ms ± 42.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [38]: %timeit df.stack().rename_axis(['Node1','Node2']).reset_index(name='Distance')
4.39 ms ± 475 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [39]: %timeit pd.concat([pd.DataFrame([[i, j, df.at[i, j]]], columns=['Node1', 'Node2', 'Distance']) for i in df.index   for j in df.columns], ignore_index=True)
31.6 s ± 1.22 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

对于大多数图形操作,如果使用图形库,您将发现巨大的优势。在这种情况下,您可以轻松地从数据帧创建一个图形,并将这些距离添加为

然后,对于所需的输出,在这种情况下,您只需要检索图形边缘的权重,这可以使用以下工具轻松完成:

或者,如果希望将结果作为数据帧:

(pd.DataFrame(weights.keys(), columns=['node1', 'node2'])
    .assign(Distance=weights.values()))

   node1  node2  Distance
0     94      4      1589
1     94     38       385
2      4     38      1280
3      4     71      1762
4      4     90      1406
5     38     71       681
6     38     90       202
7     71     90       503

如果您有兴趣对数据执行图形操作,因为您当前的任务是将邻接矩阵转换为边列表,我还建议您查看包。如果你想走那条路,然后我会使用方法添加一个答案。是的,我希望稍后使用这些数据来解决具有多个起始节点的TSP版本,因此我非常欣赏这种回答方式。Yatu已经写了一个答案,包括创建networkx图-对于TSP,我还发现了另一个可能相关的问题:numpy对元素的顺序/完整性?如果是这样,很高兴知道。美好的overview@user3184950-是,如果需要,也可以使用参数顺序。不同的顺序OP要求的是距离(与原始df中的值相同),而不是相关系数索引。这只是一些数据,具有相似的对角线。
c = np.tile(df.columns, len(df))
i = np.repeat(df.index, len(df.columns))
v = np.ravel(df)

df2 = pd.DataFrame({'Node1':i, 'Node2':c, 'Distance':v})
#6k rows
df = pd.concat([df] * 1000, ignore_index=True)
# print(df)

In [37]: %timeit df2 = pd.DataFrame({'Node1':np.repeat(df.index, len(df.columns)), 'Node2':np.tile(df.columns, len(df)), 'Distance':np.ravel(df)})
1.77 ms ± 42.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [38]: %timeit df.stack().rename_axis(['Node1','Node2']).reset_index(name='Distance')
4.39 ms ± 475 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [39]: %timeit pd.concat([pd.DataFrame([[i, j, df.at[i, j]]], columns=['Node1', 'Node2', 'Distance']) for i in df.index   for j in df.columns], ignore_index=True)
31.6 s ± 1.22 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
import networkx as nx

G = nx.from_pandas_adjacency(df)
weights = nx.get_edge_attributes(G, 'weight')
print(weights)
{(94, 4): 1589,
 (94, 38): 385,
 (4, 38): 1280,
 (4, 71): 1762,
 (4, 90): 1406,
 (38, 71): 681,
 (38, 90): 202,
 (71, 90): 503}
(pd.DataFrame(weights.keys(), columns=['node1', 'node2'])
    .assign(Distance=weights.values()))

   node1  node2  Distance
0     94      4      1589
1     94     38       385
2      4     38      1280
3      4     71      1762
4      4     90      1406
5     38     71       681
6     38     90       202
7     71     90       503