I need to do for loops to adjacency matrix in python. My goal is to find the first and second order of neighbours in matrix. I did the matrix with pysal queen contiguity. 1 is neighbour, 0 isn´t a neighbour.Code:
import pandas as pd
import pysal as ps
w = ps.queen_from_shapefile('test.shp')
Wmatrix, ids = w.full()
Wmatrix
W_DataFrame = pd.DataFrame(Wmatrix,columns=["A","B","C","D","E","F",
"G","H","I","J","K","L",
"N","M"],
index=["A","B","C","D","E","F",
"G","H","I","J","K","L",
"N","M"])
print W_DataFrame
The matrix is:
A B C D E F G H I J K L N M
A 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0
B 0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0
C 1.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 1.0 1.0 1.0 0.0 1.0
D 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0
E 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0
F 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0
G 1.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0
H 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 1.0 0.0 0.0
I 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 1.0 1.0 0.0 0.0
J 0.0 0.0 1.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 1.0
K 1.0 0.0 1.0 0.0 1.0 0.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0
L 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 1.0
N 0.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0
M 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0
For example: Position A have 3 first neighbours (C,H,K) and B is neighbour of G, and C is neighbour of B.
How do I for loops to built a dictionary of lists? Such as: {'A': ['C','H','K','G','B'] }
It looks you actually have two tasks here:
For the first task, you can use the to_dict
pandas function to convert your dataframe to a dictionary of dictionaries and then filter the sub-dictionaries according to whether their values are 0.0 or 1.0. Using your dataframe df
as an example:
d = {}
for k, subdict in df.to_dict().items():
neighbours = []
for k2, value in subdict.items():
if value:
neighbours.append(k2)
d[k] = neighbours
Now d
is a dictionary containing the first order neighbours for each key:
print(d)
{'A': ['C', 'G', 'K'],
'B': ['E', 'G', 'I'],
'C': ['A', 'D', 'H', 'J', 'K', 'L', 'M'],
'D': ['C', 'J', 'N'],
'E': ['B', 'G', 'I', 'K'],
'F': ['J', 'N'],
'G': ['A', 'B', 'E', 'K'],
'H': ['C', 'I', 'K', 'L'],
'I': ['B', 'E', 'H', 'K', 'L'],
'J': ['C', 'D', 'F', 'N', 'M'],
'K': ['A', 'C', 'E', 'G', 'H', 'I'],
'L': ['C', 'H', 'I', 'M'],
'N': ['D', 'F', 'J'],
'M': ['C', 'J', 'L']}
In order to convert this to show the second order neighbours as well you should loop over the values for each key, look up the neighbours for each value and add those to the original list of values.
def find_second_order_neighbours(d):
d2 = {}
for k, neighbours in d.items(): # loop over the dictionary
new_neighbours = set(neighbours) # create a temporary set to store all second order neighbours
for neighbour in neighbours: # loop over the original neighbours
new_neighbours = (new_neighbours | set(d[neighbour])) - {k} # add all second order neighbours ignoring duplicates (and making sure k is not its own neighbour)
d2[k] = list(new_neighbours) # update the dictionary to return
return d2
print(find_second_order_neighbours(d))
{'A': ['E', 'K', 'G', 'C', 'L', 'J', 'I', 'H', 'M', 'D', 'B'],
'B': ['E', 'G', 'K', 'L', 'A', 'I', 'H'],
'C': ['N', 'E', 'K', 'G', 'L', 'A', 'J', 'I', 'H', 'M', 'F', 'D'],
'D': ['N', 'K', 'C', 'L', 'A', 'J', 'H', 'M', 'F'],
'E': ['K', 'G', 'C', 'L', 'A', 'I', 'H', 'B'],
'F': ['N', 'C', 'J', 'M', 'D'],
'G': ['E', 'K', 'C', 'A', 'I', 'H', 'B'],
'H': ['E', 'K', 'G', 'C', 'L', 'A', 'J', 'I', 'M', 'D', 'B'],
'I': ['E', 'K', 'G', 'C', 'L', 'A', 'H', 'M', 'B'],
'J': ['N', 'K', 'C', 'L', 'A', 'H', 'M', 'F', 'D'],
'K': ['E', 'G', 'C', 'L', 'A', 'J', 'I', 'H', 'M', 'D', 'B'],
'L': ['E', 'K', 'C', 'A', 'J', 'I', 'H', 'M', 'D', 'B'],
'N': ['C', 'J', 'M', 'F', 'D'],
'M': ['N', 'K', 'C', 'L', 'A', 'J', 'I', 'H', 'D', 'F']}
EXTRA
If you are interested in more that just the second order neighbours (third order, fourth order, etc.) you can repeatedly call the find_second_order_neighbours
function to find the n
th order neighbour like so:
def find_n_order_neighbours(n, d):
while n > 1:
d = find_second_order_neighbours(d)
n -= 1
return d