Home > Back-end >  How to convert symmetric matrix to adjacency table
How to convert symmetric matrix to adjacency table

Time:05-14

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? thanks in advance)

CodePudding user response:

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

CodePudding user response:

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.

CodePudding user response:

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.

  • Related