Mathews24 Mathews24 - 4 months ago 18
Python Question

Converting dictionary with known indices to a multidimensional array

I have a dictionary with entries labelled as

{(k,i): value, ...}
. I now want to convert this dictionary into a 2d array where the value given for an element of the array at position
[k,i]
is the value from the dictionary with label
(k,i)
. The length of the rows will not necessarily be of the same size (e.g. row
k = 4
may go up to index
i = 60
while row
k = 24
may go up to index
i = 31
). Due to the asymmetry, it is fine to make all additional entries in a particular row equal to 0 in order to have a rectangular matrix.

Answer

Here's an approach -

# Get keys (as indices for output) and values as arrays
idx = np.array(d.keys())
vals = np.array(d.values())

# Get dimensions of output array based on max extents of indices
dims = idx.max(0)+1

# Setup output array and assign values into it indexed by those indices
out = np.zeros(dims,dtype=vals.dtype)
out[idx[:,0],idx[:,1]] = vals

We could also use sparse matrices to get the final output. e.g. with coordinate format sparse matrices. This would be memory efficient when kept as sparse matrices. So, the last step could be replaced by something like this -

from scipy.sparse import coo_matrix

out = coo_matrix((vals, (idx[:,0], idx[:,1])), dims).toarray()

Sample run -

In [70]: d
Out[70]: {(1, 4): 120, (2, 2): 72, (2, 3): 100, (5, 2): 88}

In [71]: out
Out[71]: 
array([[  0,   0,   0,   0,   0],
       [  0,   0,   0,   0, 120],
       [  0,   0,  72, 100,   0],
       [  0,   0,   0,   0,   0],
       [  0,   0,   0,   0,   0],
       [  0,   0,  88,   0,   0]])

To make it generic for ndarrays of any number of dimensions, we can use linear-indexing and use np.put to assign values into the output array. Thus, in our first approach, just replace the last step of assigning values with something like this -

np.put(out,np.ravel_multi_index(idx.T,dims),vals)

Sample run -

In [106]: d
Out[106]: {(1,0,0): 99, (1,0,4): 120, (2,0,2): 72, (2,1,3): 100, (3,0,2): 88}

In [107]: out
Out[107]: 
array([[[  0,   0,   0,   0,   0],
        [  0,   0,   0,   0,   0]],

       [[ 99,   0,   0,   0, 120],
        [  0,   0,   0,   0,   0]],

       [[  0,   0,  72,   0,   0],
        [  0,   0,   0, 100,   0]],

       [[  0,   0,  88,   0,   0],
        [  0,   0,   0,   0,   0]]])