简体   繁体   中英

Optimal way to get adjacency matrix from 2d cell-grid numpy array

Given an array of values:

x = array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])

I would like to know if there is an optimal way to easily obtain its equivalent adjacency matrix:

M = array([[ inf,   1.,  inf,   3.,   4.,  inf,  inf,  inf,  inf],
           [  0.,  inf,   2.,   3.,   4.,   5.,  inf,  inf,  inf],
           [ inf,   1.,  inf,  inf,   4.,   5.,  inf,  inf,  inf],
           [  0.,   1.,  inf,  inf,   4.,  inf,   6.,   7.,  inf],
           [  0.,   1.,   2.,   3.,  inf,   5.,   6.,   7.,   8.],
           [ inf,   1.,   2.,  inf,   4.,  inf,  inf,   7.,   8.],
           [ inf,  inf,  inf,   3.,   4.,  inf,  inf,   7.,  inf],
           [ inf,  inf,  inf,   3.,   4.,   5.,   6.,  inf,   8.],
           [ inf,  inf,  inf,  inf,   4.,   5.,  inf,   7.,  inf]])

The idea really is to build an object in networx with which to work, and I am looking to obtain the adjacency matrix of a cell grid to be able to load that matrix in networkx, but if there is a better way to achieve it I am open to suggestions. According to documentation I have been able to find the grid_2d_graph () function that allows dimensioning the graph that I want given the n rows and m columns of the original matrix, however I want the weight to go from one node to another (if possible), be the value of the array that the target node occupies.

EDIT

Although the proposed example is a particular case (square matrix and ordered values), the problem arises for any matrix, with dimensions not necessarily equal and random values.

I think this is what you're after:

def create_adj_mat(x):
    y = np.ones([x.size,np.max(x)+1]) * np.inf #initialize
    for I,i in enumerate(np.ravel(x)): 
        #get adjacent values of y and x points
        d = x[max(0,I//x.shape[1]-1):min(x.shape[0],I//x.shape[1]+2),  
              max(0,I%x.shape[1]-1):min(x.shape[1],I%x.shape[1]+2)]
        y[I,np.ravel(d)] = np.ravel(d) 
    np.fill_diagonal(y,np.inf) #remove i,i points
    return y

It iterates through the ravelled values of your input matrix and finds the adjacent values (-1 and +2 offset, +2 because of python indexing) and sets the array y according to these values.

When you pass your matrix, you get:

x = np.array([[0, 1, 2], 
            [3, 4, 5], 
            [6, 7, 8]])
y = create_adj_mat(x)
print(y)

array([[inf,  1., inf,  3.,  4., inf, inf, inf, inf],
   [ 0., inf,  2.,  3.,  4.,  5., inf, inf, inf],
   [inf,  1., inf, inf,  4.,  5., inf, inf, inf],
   [ 0.,  1., inf, inf,  4., inf,  6.,  7., inf],
   [ 0.,  1.,  2.,  3., inf,  5.,  6.,  7.,  8.],
   [inf,  1.,  2., inf,  4., inf, inf,  7.,  8.],
   [inf, inf, inf,  3.,  4., inf, inf,  7., inf],
   [inf, inf, inf,  3.,  4.,  5.,  6., inf,  8.],
   [inf, inf, inf, inf,  4.,  5., inf,  7., inf]])

EDIT

Assuming the representation of a non-ordered, non-square matrix, I've made a minor change to my code to look like this:

def create_adj_mat(x):
    y = np.ones([np.max(x)+1,np.max(x)+1]) * np.inf #initialize
    for I,i in enumerate(np.ravel(x)): 
        #get adjacent values of y and x points
        d = x[max(0,I//x.shape[1]-1):min(x.shape[0],I//x.shape[1]+2),  
              max(0,I%x.shape[1]-1):min(x.shape[1],I%x.shape[1]+2)] 
        y[i,np.ravel(d)] = np.ravel(d) 
    np.fill_diagonal(y,np.inf) #remove i,i points
    return y

Then, when you pass such an array:

d = np.array([[10,3],[5,12],[2,1]])
create_adj_mat(d)
array([[inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
   [inf, inf,  2., inf, inf,  5., inf, inf, inf, inf, inf, inf, 12.],
   [inf,  1., inf, inf, inf,  5., inf, inf, inf, inf, inf, inf, 12.],
   [inf, inf, inf, inf, inf,  5., inf, inf, inf, inf, 10., inf, 12.],
   [inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
   [inf,  1.,  2.,  3., inf, inf, inf, inf, inf, inf, 10., inf, 12.],
   [inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
   [inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
   [inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
   [inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
   [inf, inf, inf,  3., inf,  5., inf, inf, inf, inf, inf, inf, 12.],
   [inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf],
   [inf,  1.,  2.,  3., inf,  5., inf, inf, inf, inf, 10., inf, inf]])

Using networkx to construct the implied network from the array, we specify the weight of each di-graph edge to be the node number of the target node. Then, we can use the adj_matrix() function to generate the matrix:

import networkx as nx
import numpy as np

x = np.arange(9).reshape(3, 3)
G = nx.DiGraph()
# Ensure nodes sort order
G.add_nodes_from(np.arange(9))
i1, j1 = x.shape
for i in range(i1):
    for j in range(j1):
        if i < i1-1:
            G.add_edge(x[i,j], x[i+1,j], weight=x[i+1,j])
            G.add_edge(x[i+1,j], x[i,j], weight=x[i,j])
            if j > 0:
                G.add_edge(x[i,j], x[i+1,j-1], weight=x[i+1,j-1])
                G.add_edge(x[i+1,j-1], x[i,j], weight=x[i,j])
        if j < j1-1:
            G.add_edge(x[i,j], x[i,j+1], weight=x[i,j+1])
            G.add_edge(x[i,j+1], x[i,j], weight=x[i,j])
            if i < i1-1:
                G.add_edge(x[i,j], x[i+1,j+1], weight=x[i+1,j+1])
                G.add_edge(x[i+1,j+1], x[i,j], weight=x[i,j])
            if i > 0:
                G.add_edge(x[i,j], x[i-1,j+1], weight=x[i-1,j+1])
                G.add_edge(x[i-1,j+1], x[i,j], weight=x[i,j])
am1 = nx.adj_matrix(G).todense().astype(float)
np.putmask(am1, am1==0, np.inf)
print(am1)

Output:

# [[inf  1. inf  3.  4. inf inf inf inf]
#  [inf inf  2.  3.  4.  5. inf inf inf]
#  [inf  1. inf inf  4.  5. inf inf inf]
#  [inf  1. inf inf  4. inf  6.  7. inf]
#  [inf  1.  2.  3. inf  5.  6.  7.  8.]
#  [inf  1.  2. inf  4. inf inf  7.  8.]
#  [inf inf inf  3.  4. inf inf  7. inf]
#  [inf inf inf  3.  4.  5.  6. inf  8.]
#  [inf inf inf inf  4.  5. inf  7. inf]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM