2

I have a dictionary of the following form:

{(2, 2): 387, (1, 2): 25, (0, 1): 15, (2, 1): 12, (2, 6): 5, (6, 2): 5, (4, 2): 4, (3, 4): 4, (5, 2): 2, (0, 2): 1}

where key represents coordinates to the matrix, and value is actual value to be added at the coordinates.

At the moment I create and populate matrix in the following way:

import numpy as np

def build_matrix(data, n):
   M = np.zeros(shape=(n, n), dtype=np.float64)
   for key, val in data.items():
      (row, col) = key
      M[row][col] = val

Is there a way to do it shorter, using numpy'a API? I looked at np.array(), np.asarray() bit none seem to fit my needs.

Mark
  • 6,052
  • 8
  • 61
  • 129

2 Answers2

1

The shortest version given n and the input dictionary itself seems to be -

M = np.zeros(shape=(n, n), dtype=np.float64)
M[tuple(zip(*d.keys()))] = list(d.values())

That tuple(zip(*d.keys())) is basically transposing nested items and then packing into tuples as needed for integer-indexing into NumPy arrays. More info on transposing nested items.

Generic case

To handle generic cases, when n is not given and is required to generated based on the extents of the keys alongwith dtype from dictionary values, it would be -

idx_ar = np.array(list(d.keys()))
out_shp = idx_ar.max(0)+1
data = np.array(list(d.values()))
M = np.zeros(shape=out_shp, dtype=data.dtype)
M[tuple(idx_ar.T)] = data
Divakar
  • 218,885
  • 19
  • 262
  • 358
  • thanks for feedback. Could you explain the meaning of `*list(d.keys()` ? So I understand that `list()` turns its input into a list, given the input is iterative, but what does `*` do? – Mark Dec 09 '19 at 22:09
  • @Mark Added some comments on it. – Divakar Dec 09 '19 at 22:15
0

If you don't mind using scipy, what you've basically created is a sparse dok_matrix (Dictionary of Keys)

from scipy.sparse import dok_matrix

out = dok_matrix((n, n))
out.update(data)
out = out.todense()
Daniel F
  • 13,620
  • 2
  • 29
  • 55