Convert numpy 1D array to an adjacency matrix

Question:

How can I convert a numpy 1D array:

np.array([1,2,3,4,5,6,7,8,9,10])

to an adjacency like matrix, i.e with zeroes in the diagonal? Desired output:

[[0 0 0 0 0]
 [1 0 0 0 0]
 [2 5 0 0 0]
 [3 6 8 0 0]
 [4 7 9 10 0]]

Output could also be a matrix with both upper an lower triangle.
I’ve tried with numpy.triu and numpy.tril but not all values get in the correct location.

Asked By: lindak

||

Answers:

A little messy, but gets the job done:

def make_triangular_matrix(values):
  # Compute the appropriate side length for the given input ...
  # good old quadratic equation :-)
  n = (np.sqrt(8*len(values) + 1) - 1) / 2
  if not n.is_integer(): raise Exception("Invalid input length")
  side_length = int(n) + 1

  out = np.zeros((side_length, side_length), dtype=values.dtype)

  # Only interested in the region BELOW the diagonal,
  # which excludes the first row and last column ...
  lower = out[1:,:-1]

  # Assign the values to the appropriate indices (see note about .T)
  lower.T[np.triu_indices_from(lower)] = values

  return out

make_triangular_matrix(np.array([1,2,3,4,5,6,7,8,9,10]))

Note that it’s a little more natural in row-major mode to construct the upper triangular region, which is why we fill in lower.T using the upper-triangular indices.

Answered By: motto

Another possible solution:

n = 5

v = np.array([3, 6, 7, 10, 12, 5, 8, 19, 21, 23])

a = np.tril(np.ones((n, n), dtype='int'), -1)
b = np.cumsum(np.roll(a.sum(axis=0), 1))
b[-1] = 0
out = np.cumsum(a + np.diagflat(b), axis=0)
out = np.tril(out, -1)
np.tril(v[out-1], -1)

Output:

array([[ 0,  0,  0,  0,  0],
       [ 3,  0,  0,  0,  0],
       [ 6, 12,  0,  0,  0],
       [ 7,  5, 19,  0,  0],
       [10,  8, 21, 23,  0]])
Answered By: PaulS
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.