Convert 1d array to lower triangular matrix

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


Convert 1d array to lower triangular matrix



I would like to convert a 1 dimensional array into a lower, zero diagonal matrix while keeping all the digits.



I am aware of numpy.tril function but it replaces some of the elements with zeros. I need to expand the matrix to contain all the original digits.


numpy.tril



For example:



[10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12]



Should be


0
10 0
20 40 0
46 33 14 0
12 46 52 30 0
59 18 11 22 30 0
2 11 58 22 72 12 0




3 Answers
3



With the input array holding all the values as required to fill up the lower diagonal places, here's one approach with masking -


masking


def fill_lower_diag(a):
n = int(np.sqrt(len(a)*2))+1
mask = np.tri(n,dtype=bool, k=-1) # or np.arange(n)[:,None] > np.arange(n)
out = np.zeros((n,n),dtype=int)
out[mask] = a
return out



Sample run -


In [82]: a
Out[82]:
array([10, 20, 40, 46, 33, 14, 12, 46, 52, 30, 59, 18, 11, 22, 30, 2, 11,
58, 22, 72, 12])

In [83]: fill_lower_diag(a)
Out[83]:
array([[ 0, 0, 0, 0, 0, 0, 0],
[10, 0, 0, 0, 0, 0, 0],
[20, 40, 0, 0, 0, 0, 0],
[46, 33, 14, 0, 0, 0, 0],
[12, 46, 52, 30, 0, 0, 0],
[59, 18, 11, 22, 30, 0, 0],
[ 2, 11, 58, 22, 72, 12, 0]])



Timings on large array with 5k x 5k shape -


5k x 5k


In [146]: np.random.seed(0)

In [147]: n = 5000

In [148]: a = np.random.randint(0,9,n*(n+1)/2)

In [149]: %timeit tril_indices_app(a) #@Brenlla's solution
1 loop, best of 3: 218 ms per loop

In [151]: %timeit fill_lower_diag(a) # From this post
10 loops, best of 3: 43.1 ms per loop





Yep, mask indexing can be much faster and more memory efficient (provided you are indexing enough elements). My aproach would only be competitive for a small k relative to the triangular matrix size
– Brenlla
Jul 20 at 10:19




k





@Brenlla I think its also about generating those indices vs getting the mask that showing the difference, specially with decent to large sized arrays.
– Divakar
Jul 20 at 10:29





Yes, that's true. In your timing code shoudn't it be n*(n-1)?
– Brenlla
Jul 20 at 10:39


n*(n-1)





@Brenlla Ah yes thanks. It would generate 5001 x 5001 shaped array. Timings shouldn't change much.
– Divakar
Jul 20 at 10:42



You could also use the numpy function np.tril_indices:


np.tril_indices


arr = np.array([10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12])
n = int(np.sqrt(len(arr)*2))+1



Generate zeros matrix and fill the lower part with your values:


idx = np.tril_indices(n, k=-1, m=n)
matrix = np.zeros((n,n)).astype(int)
matrix[idx] = arr
array([[ 0, 0, 0, 0, 0, 0, 0],
[10, 0, 0, 0, 0, 0, 0],
[20, 40, 0, 0, 0, 0, 0],
[46, 33, 14, 0, 0, 0, 0],
[12, 46, 52, 30, 0, 0, 0],
[59, 18, 11, 22, 30, 0, 0],
[ 2, 11, 58, 22, 72, 12, 0]])



You can also try the below function to get the list.


import pprint

def get_triangled_list(l, rows, typ='lower'):
if type(l) is not list:
print 'First parameter should be a list'
return None

if type(rows) is not int:
print 'Second parameter should be a list'
return None

if not(typ == 'lower' or typ == 'upper'):
print 'ERROR:', typ, 'is not allowed type'
return None

new_l =
length = len(l)
num_items = ((rows-1) * rows)/ 2

if length != num_items:
print 'ERROR: ', 'There should be exactly', num_items, 'items for ', rows, 'rows, found', length, 'items.'
return None

if typ == 'upper':
for i in range(rows):
temp_l = [0]*(i+1) + [l.pop(0) for j in range(7-(i+1))]
new_l.append(temp_l)
elif typ=='lower':
for i in range(rows):
temp_l = [l.pop(0) for j in range(i)] + [0]*(rows-i)
new_l.append(temp_l)

return new_l

if __name__ == '__main__':
l = [10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12]

# TEST CASE 1 (LOWER TRIANGLE, default)
new_lower = get_triangled_list(l, 7)
pprint.pprint(new_lower)
print('n')

# TEST CASE 2 (UPPER TRIANGLE, passing one more parameter)
l = [10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12]
new_upper = get_triangled_list(l, 7, 'upper')
pprint.pprint(new_upper)


[[0, 0, 0, 0, 0, 0, 0],
[10, 0, 0, 0, 0, 0, 0],
[20, 40, 0, 0, 0, 0, 0],
[46, 33, 14, 0, 0, 0, 0],
[12, 46, 52, 30, 0, 0, 0],
[59, 18, 11, 22, 30, 0, 0],
[2, 11, 58, 22, 72, 12, 0]]


[[0, 10, 20, 40, 46, 33, 14],
[0, 0, 12, 46, 52, 30, 59],
[0, 0, 0, 18, 11, 22, 30],
[0, 0, 0, 0, 2, 11, 58],
[0, 0, 0, 0, 0, 22, 72],
[0, 0, 0, 0, 0, 0, 12],
[0, 0, 0, 0, 0, 0, 0]]






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Arduino Mega cannot recieve any sketches, stk500_recv() programmer is not responding

Visual Studio Code: How to configure includePath for better IntelliSense results

C++ virtual function: Base class function is called instead of derived