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