Convert dictionary with coordinates and values to 2D array

Viewed 651

Assume the next dictionary is given:

{(0, 0): 1, (1, 1): 12, (2, 2): 802, (3, 3): 1687, (4, 4): 11, (5, 4): 4, (6, 5): 593, (7, 4): 4}

In the dictionary above each key displays a point in the matrix (x, y) and a value displays the value found in the matrix. How could I construct an array that will contain the values located at each point x, y?

According to the dictionary above the expected result is:

array([[   1,    0,    0,    0,    0,    0],
       [   0,   12,    0,    0,    0,    0],
       [   0,    0,  802,    0,    0,    0],
       [   0,    0,    0, 1687,    0,    0],
       [   0,    0,    0,    0,   11,    0],
       [   0,    0,    0,    0,    4,    0],
       [   0,    0,    0,    0,    0,  593],
       [   0,    0,    0,    0,    4,    0]])
9 Answers

You could use np.add.at, defining the shape of the array beforehand from the keys:

d = {(0, 0): 1, (1, 1): 12, (2, 2): 802, (3, 3): 1687, (4, 4): 11, 
     (5, 4): 4, (6, 5): 593, (7, 4): 4}

i,j = zip(*d.keys())
a = np.zeros((max(i)+1,max(j)+1), np.int32)
np.add.at(a, tuple((i,j)), tuple(d.values()))

a
array([[   1,    0,    0,    0,    0,    0],
       [   0,   12,    0,    0,    0,    0],
       [   0,    0,  802,    0,    0,    0],
       [   0,    0,    0, 1687,    0,    0],
       [   0,    0,    0,    0,   11,    0],
       [   0,    0,    0,    0,    4,    0],
       [   0,    0,    0,    0,    0,  593],
       [   0,    0,    0,    0,    4,    0]])

Use a coo sparse matrix and convert to array afterwards:

from scipy.sparse import coo_matrix

data= {(0, 0): 1, (1, 1): 12, (2, 2): 802, (3, 3): 1687, (4, 4): 11, (5, 4): 4, (6, 5): 593, (7, 4): 4}

row, col, fill = zip(*[(*k, v) for k, v in data.items()])

result = coo_matrix((fill, (row, col)), shape=(8, 6)).toarray()
print(result)

Output

[[   1    0    0    0    0    0]
 [   0   12    0    0    0    0]
 [   0    0  802    0    0    0]
 [   0    0    0 1687    0    0]
 [   0    0    0    0   11    0]
 [   0    0    0    0    4    0]
 [   0    0    0    0    0  593]
 [   0    0    0    0    4    0]]

My 2cents:

n=np.zeros([max(d.keys(), key=lambda x:x[0])[0]+1,max(d.keys(), key=lambda x:x[1])[1]+1], int)

for i,k in d.items():
    n[i[0], i[1]]=k

>>>print(n)

array([[   1,    0,    0,    0,    0,    0],
       [   0,   12,    0,    0,    0,    0],
       [   0,    0,  802,    0,    0,    0],
       [   0,    0,    0, 1687,    0,    0],
       [   0,    0,    0,    0,   11,    0],
       [   0,    0,    0,    0,    4,    0],
       [   0,    0,    0,    0,    0,  593],
       [   0,    0,    0,    0,    4,    0]])

That's just a dictionary of keys (dok) representation for sparse matrices. So . . .

from scipy.sparse import dok_matrix

out = dok_matrix((8, 8), dtype = int)
out._update(d)
out.todense()

Out[]: 
matrix([[   1,    0,    0,    0,    0,    0,    0,    0],
        [   0,   12,    0,    0,    0,    0,    0,    0],
        [   0,    0,  802,    0,    0,    0,    0,    0],
        [   0,    0,    0, 1687,    0,    0,    0,    0],
        [   0,    0,    0,    0,   11,    0,    0,    0],
        [   0,    0,    0,    0,    4,    0,    0,    0],
        [   0,    0,    0,    0,    0,  593,    0,    0],
        [   0,    0,    0,    0,    4,    0,    0,    0]])

The most efficient way of extracting values of any iterable in pure numpy is np.fromiter. And here is a good occasion to use it:

Approach 1

d = {(0, 0): 1, (1, 1): 12, (2, 2): 802, (3, 3): 1687, (4, 4): 11, (5, 4): 4, (6, 5): 593, (7, 4): 4}
X = np.zeros((8,8), dtype=int)
idx = np.fromiter(d, dtype='i,i').view(int).reshape(-1, 2)
vals = np.fromiter(d.values(), dtype=float)
X[idx[:,0], idx[:,1]] = vals

Remark: I mean extracting values of iterable that corresponds to some shape. itertools.chain is needed in addition otherwise.

Approach 2

itertools.chain is a very fast way to flatten iterables which gives a significant boost to np.fromiter. It has no requirements for sizes of iterable items. This works 2.5x times faster than previous alternative:

import itertools
X = np.zeros((8,8), dtype=int)
idx = np.fromiter(itertools.chain(*d.keys()), dtype=int).reshape(-1,2)
vals = np.fromiter(d.values(), dtype=float)
X[idx[:,0], idx[:,1]] = vals

Approach 3

zip could be used instead of itertools.chain but it still little bit (5-10%) slower than approach 2:

X = np.zeros((8,8), dtype=int)
idx1, idx2 = zip(*d.keys())
vals = np.fromiter(d.values(), dtype=float)
X[idx1, idx2] = vals

If the array size is known already, you can do this,

import numpy as np

arr = np.zeros((8, 6), dtype='int')
d = {(0, 0): 1, (1, 1): 12, (2, 2): 802, (3, 3): 1687, (4, 4): 11, (5, 4): 4, (6, 5): 593, (7, 4): 4}

for key, val in d.items():
    arr[key[0]][key[1]] = val
    
array([[   1,    0,    0,    0,    0,    0],
   [   0,   12,    0,    0,    0,    0],
   [   0,    0,  802,    0,    0,    0],
   [   0,    0,    0, 1687,    0,    0],
   [   0,    0,    0,    0,   11,    0],
   [   0,    0,    0,    0,    4,    0],
   [   0,    0,    0,    0,    0,  593],
   [   0,    0,    0,    0,    4,    0]])
    import numpy as np

    cols = max(key[0] for key in d) + 1
    rows = max(key[1] for key in d) + 1

    mat = np.zeros((cols, rows), dtype=np.int)
    for point in d: mat[point] = d[point]

    print(mat)

####### result #######
[[   1    0    0    0    0    0]
 [   0   12    0    0    0    0]
 [   0    0  802    0    0    0]
 [   0    0    0 1687    0    0]
 [   0    0    0    0   11    0]
 [   0    0    0    0    4    0]
 [   0    0    0    0    0  593]
 [   0    0    0    0    4    0]]

Yet another solution is:

import numpy as np

d = {(0, 0): 1, (1, 1): 12, (2, 2): 802, (3, 3): 1687, (4, 4): 11, (5, 4): 4, (6, 5): 593, (7, 4): 4}

X = np.zeros((8,8))
X[tuple(np.array(list(d.keys())).T)] = list(d.values())

Which output:

array([[   1,    0,    0,    0,    0,    0,    0,    0],
       [   0,   12,    0,    0,    0,    0,    0,    0],
       [   0,    0,  802,    0,    0,    0,    0,    0],
       [   0,    0,    0, 1687,    0,    0,    0,    0],
       [   0,    0,    0,    0,   11,    0,    0,    0],
       [   0,    0,    0,    0,    4,    0,    0,    0],
       [   0,    0,    0,    0,    0,  593,    0,    0],
       [   0,    0,    0,    0,    4,    0,    0,    0]], dtype=uint32)

Use tuple of numpy arrays which can be directly passed to the matrix to get the elements and then assign the values of the dictionary.

Try this

import numpy as np
matrix = np.zeros((8,6))
your_dict = {(0, 0): 1, (1, 1): 12, (2, 2): 802, (3, 3): 1687, (4, 4): 11, (5,4): 4, (6, 5): 593, (7, 4): 4}
for key, value in your_dict.items():
    matrix[key[0],key[1]] = value

In case your matrix is other size consider changing the zeros initialization

Output

[[   1    0    0    0    0    0]
 [   0   12    0    0    0    0]
 [   0    0  802    0    0    0]
 [   0    0    0 1687    0    0]
 [   0    0    0    0   11    0]
 [   0    0    0    0    4    0]
 [   0    0    0    0    0  593]
 [   0    0    0    0    4    0]]
Related