Reputation: 355
I have a dictionary containing distances information in the following format
distances = {"a": {"b": 0.2, "c": 0.4}, "b": {"c": 0.6}}
I would like to build a distance matrix based on the order in a list:
order = ["a", "b", "c"]
Thus the desired output should look something like this:
[
0, 0.2, 0.4
0.2 , 0, 0.6
0.4, 0.6, 0
]
I've tried the following but I'm not sure how to move forward. Any help is appreciated
dist = np.zeros((len(order), len(order)))
for index1, member1 in enumerate(order):
curr = distances.get(member1, {})
for index2, member2 in enumerate(order):
val = curr.get(member2, None)
if member2 not in curr:
val = None
dist[index1, index2] = val
Upvotes: 0
Views: 392
Reputation: 577
Can you try this and let me know whether it suits your requirement.
distances = {"a": {"b": 0.2, "c": 0.4}, "b": {"c": 0.6}}
order = ["a", "b", "c"]
N = len(order)
#Create N*N array of 0's
dist = [[0]*N for _ in range(N)]
# New dict for array indexing
dd = {'a':0,'b':1,'c':2}
def set_items(x,y,val):
if x!=y :
dist[x][y] = dist[y][x] = val
#dictionary comprehension of the distances dict.
[set_items(dd[k],dd[k1],v1) for k,v in distances.items() for k1,v1 in v.items()]
print(dist)
#### Output ####
[
[0, 0.2, 0.4],
[0.2, 0, 0.6],
[0.4, 0.6, 0]
]
Upvotes: 0
Reputation: 4544
I am assuming that you're guaranteed to have the distance defined in one way or the other. So I suggest using a try/except/finally
block where you can flip which way you're looking the items up.
import numpy as np
distances = {"a": {"b": 0.2, "c": 0.4}, "b": {"c": 0.6}}
order = ["a", "b", "c"]
dist = np.zeros((len(order), len(order)))
for i, member1 in enumerate(order):
for j, member2 in enumerate(order):
if member1 != member2:
try:
d = distances[member1][member2]
except KeyError as e:
d = distances[member2][member1]
finally:
dist[i][j] = d
print(dist)
# [[0. 0.2 0.4]
# [0.2 0. 0.6]
# [0.4 0.6 0. ]]
Upvotes: 0
Reputation: 170
this should work, but assumes that your dictionary is ordered the same way as your list and all pairs exist:
l = len(ordered_list)
result = np.zeros((l, l))
for i in range(l):
for j in range(l):
if i == j:
continue
elif i < j:
result[i][j] = distances[ordered_list[i]][ordered_list[j]]
else:
result[i][j] = distances[ordered_list[j]][ordered_list[i]]
if this assumption does not hold, a more robust solution is
l = len(ordered_list)
result = np.zeros((l, l))
for i in range(l):
for j in range(l):
if i == j:
continue
try:
result[i][j] = distances[ordered_list[i]][ordered_list[j]]
except KeyError:
try:
result[i][j] = distances[ordered_list[j]][ordered_list[i]]
except:
raise Exception("pair {0}, {1} does not exist. ". format(ordered_list[i],ordered_list[j]))
Upvotes: 0
Reputation: 841
You can do this:
distances = {"a": {"b": 0.2, "c": 0.4}, "b": {"c": 0.6}}
order = ["a", "b", "c"]
dist = np.zeros((len(order), len(order)))
for index1, member1 in enumerate(order):
curr = distances.get(member1, {})
for index2, member2 in enumerate(order):
dist[index1, index2] = curr.get(member2, 0)
print(dist + np.swapaxes(dist, 0, 1))
Upvotes: 1