'How to convert symmetric matrix to adjacency table

How could I convert symmetric matrix:

  A B C D
A 1 2 3 4
B 2 1 2 3
C 3 2 1 2
D 4 3 2 1

into adjacency matrix?:

A A 1
A B 2
A C 3 
A D 4
B A 3
B B 1
B C 2
B D 3
C A 3
C C 1
C D 2
D A 4
D B 3
D C 2
D D 1

Is there any function?



Solution 1:[1]

Assuming a pandas dataframe as input, you can use numpy to get the triu_indices:

import pandas as pd
import numpy as np

l = [[1, 2, 3, 4], [2, 1, 2, 3], [3, 2, 1, 2], [4, 3, 2, 1]]
df = pd.DataFrame(l, index=list('ABCD'), columns=list('ABCD'))

#    A  B  C  D
# A  1  2  3  4
# B  2  1  2  3
# C  3  2  1  2
# D  4  3  2  1

a = df.to_numpy()
x,y = np.triu_indices(len(df))

out = pd.DataFrame({'x': df.index[x], 'y':  df.columns[y], 'value': a[x,y]})

output:

   x  y  value
0  A  A      1
1  A  B      2
2  A  C      3
3  A  D      4
4  B  B      1
5  B  C      2
6  B  D      3
7  C  C      1
8  C  D      2
9  D  D      1
all combinations
df.reset_index().melt('index', var_name='column')

output:

   index column  value
0      A      A      1
1      B      A      2
2      C      A      3
3      D      A      4
4      A      B      2
5      B      B      1
6      C      B      2
7      D      B      3
8      A      C      3
9      B      C      2
10     C      C      1
11     D      C      2
12     A      D      4
13     B      D      3
14     C      D      2
15     D      D      1

or, for a different order:

df.stack().rename_axis(['index', 'columns']).reset_index(name='value')

output:

   index columns  value
0      A       A      1
1      A       B      2
2      A       C      3
3      A       D      4
4      B       A      2
5      B       B      1
6      B       C      2
7      B       D      3
8      C       A      3
9      C       B      2
10     C       C      1
11     C       D      2
12     D       A      4
13     D       B      3
14     D       C      2
15     D       D      1

Solution 2:[2]

Another solution is to use pandas.stack() and reset the index values:

import pandas as pd
import numpy as np

l = [[1, 2, 3, 4], [2, 1, 2, 3], [3, 2, 1, 2], [4, 3, 2, 1]]
df = pd.DataFrame(l, index=list('ABCD'), columns=list('ABCD'))

#    A  B  C  D
# A  1  2  3  4
# B  2  1  2  3
# C  3  2  1  2
# D  4  3  2  1

df = df.stack().reset_index()
df['ordered-name'] = df.apply(lambda x: '-'.join(sorted([x['level_0'],x['level_1']])),axis=1)
df = df.drop_duplicates(['ordered-name'])
df.drop(['ordered-name'], axis=1, inplace=True)
#    level_0  level_1  0
# 0        A        A  1
# 1        A        B  2
# 2        A        C  3
# 3        A        D  4
# 4        B        B  1
# 5        B        C  2
# 6        B        D  3
# 7        C        C  1
# 8        C        D  2
# 9        D        D  1

You can change the names of the columns as you wish.

Solution 3:[3]

It actually already is an adjacency matrix (as you would use it for a directed graph). I guess what you're looking for an Adjacency List or considering your example an Adjacency Map (for an undirected graph). I'm not sure if there is a built-in function for such a conversion (assuming you're using pandas dataframes considering the used tags). The easiest way of doing it is just reading the top (or just the bottom) triangle of the matrix which shouldn't take up too many iterations in a loop and just constructing it that way.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 David Hutter