我想将节点和距离矩阵转换为 table,其中包含节点 1、节点 2 的列以及它们之间的距离
I want to convert a matrix of nodes and distances into a table with columns for node1, node2 and the distance between them
我正在处理 csv 文件,其中包含每个节点的 header 和每个节点的对应行,每个数据字段对应于两个节点之间的差异,如下所示:
Blank
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
(在此上下文中 0 表示没有连接,因为它们是相同的节点或它们未连接)
我想更改布局,使其类似于:
Node1
Node2
Distance
4
4
0
4
38
1280
4
71
1762
以此类推,包括所有节点及其连接
是否有 pythonic 方式来执行此操作?
我想要的是使用 Pandas stack,例如
import numpy as np
import pandas as pd
A = np.abs(1 - np.corrcoef( np.random.random( size=(8,8) ))) * 100
A 只是有一些随机的或多或少相似的数据。
我们现在用
创建一个 df
df = pd.DataFrame(A, columns = [ "node_" + str(i) for i in range(A.shape[0])])
node_0 node_1 node_2 node_3 node_4 node_5 \
0 1.110223e-14 177.640823 94.528739 102.894884 75.716800 16.959874
1 1.776408e+02 0.000000 100.594166 69.032398 106.857164 180.845071
2 9.452874e+01 100.594166 0.000000 143.128873 154.447302 114.711230
3 1.028949e+02 69.032398 143.128873 0.000000 25.162778 129.170641
4 7.571680e+01 106.857164 154.447302 25.162778 0.000000 74.135700
5 1.695987e+01 180.845071 114.711230 129.170641 74.135700 0.000000
6 1.424585e+02 74.925019 70.156519 70.914395 125.433304 171.546764
7 8.862326e+01 67.220779 139.488270 61.680713 58.115007 98.620041
你可以df.stack()
df_stacked = df.stack()
您可以使用 pd.DataFrame( df_stacked )
将其设为数据框
在这里使用 DataFrame.stack
以获得更好的性能,例如 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)
对于大多数图形操作,如果您使用图形库,您会发现巨大的优势。在这种情况下,您可以轻松地从数据框创建一个图形并将这些距离添加为 edge weights.
然后对于所需的输出,您只需要在这种情况下检索图边的权重,这可以使用 NetworkX 轻松完成:
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
我正在处理 csv 文件,其中包含每个节点的 header 和每个节点的对应行,每个数据字段对应于两个节点之间的差异,如下所示:
Blank | 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 |
(在此上下文中 0 表示没有连接,因为它们是相同的节点或它们未连接)
我想更改布局,使其类似于:
Node1 | Node2 | Distance |
---|---|---|
4 | 4 | 0 |
4 | 38 | 1280 |
4 | 71 | 1762 |
以此类推,包括所有节点及其连接
是否有 pythonic 方式来执行此操作?
我想要的是使用 Pandas stack,例如
import numpy as np
import pandas as pd
A = np.abs(1 - np.corrcoef( np.random.random( size=(8,8) ))) * 100
A 只是有一些随机的或多或少相似的数据。
我们现在用
创建一个 dfdf = pd.DataFrame(A, columns = [ "node_" + str(i) for i in range(A.shape[0])])
node_0 node_1 node_2 node_3 node_4 node_5 \
0 1.110223e-14 177.640823 94.528739 102.894884 75.716800 16.959874
1 1.776408e+02 0.000000 100.594166 69.032398 106.857164 180.845071
2 9.452874e+01 100.594166 0.000000 143.128873 154.447302 114.711230
3 1.028949e+02 69.032398 143.128873 0.000000 25.162778 129.170641
4 7.571680e+01 106.857164 154.447302 25.162778 0.000000 74.135700
5 1.695987e+01 180.845071 114.711230 129.170641 74.135700 0.000000
6 1.424585e+02 74.925019 70.156519 70.914395 125.433304 171.546764
7 8.862326e+01 67.220779 139.488270 61.680713 58.115007 98.620041
你可以df.stack()
df_stacked = df.stack()
您可以使用 pd.DataFrame( df_stacked )
在这里使用 DataFrame.stack
以获得更好的性能,例如 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)
对于大多数图形操作,如果您使用图形库,您会发现巨大的优势。在这种情况下,您可以轻松地从数据框创建一个图形并将这些距离添加为 edge weights.
然后对于所需的输出,您只需要在这种情况下检索图边的权重,这可以使用 NetworkX 轻松完成:
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