Elhanan Schwarts
Elhanan Schwarts

Reputation: 383

Convert dictionary with coordinates and values to 2D array

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]])

Upvotes: 2

Views: 1136

Answers (9)

mathfux
mathfux

Reputation: 5949

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

Upvotes: 1

yatu
yatu

Reputation: 88285

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]])

Upvotes: 2

Daniel F
Daniel F

Reputation: 14399

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]])

Upvotes: 1

aarribas12
aarribas12

Reputation: 574

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]]

Upvotes: 0

David
David

Reputation: 8318

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.

Upvotes: 0

IoaTzimas
IoaTzimas

Reputation: 10624

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]])

Upvotes: 1

Dani Mesejo
Dani Mesejo

Reputation: 61920

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]]

Upvotes: 1

Joonyoung Park
Joonyoung Park

Reputation: 484

    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]]

Upvotes: 0

Sreeram TP
Sreeram TP

Reputation: 11927

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]])

Upvotes: 0

Related Questions