create a matrix from array of elements under diago

2019-07-22 01:41发布

I would like to create a matrix using a list whose elements would be the elements of the matrix under the diagonal.

import numpy as np
x1 = np.array([0.9375, 0.75, 0.4375, 0.0, 0.9375, 0.75, 0.4375, 0.9375, 0.75, 0.9375])
x1

the matrix I would like to have is

array([[ 1.    ,  0.9375,  0.75  ,  0.4375,  0.    ],
   [ 0.9375,  1.    ,  0.9375,  0.75  ,  0.4375],
   [ 0.75  ,  0.9375,  1.    ,  0.9375,  0.75  ],
   [ 0.4375,  0.75  ,  0.9375,  1.    ,  0.9375],
   [ 0.    ,  0.4375,  0.75  ,  0.9375,  1.    ]])

I thought you could do this with np.tril but it gives a result I do not expect.

mat = np.tril(x1, k = -1  )
print(mat)

what am I missing ?

I apologize in advance if this is a trivial question but I could not figure out how to it without looping.

3条回答
相关推荐>>
2楼-- · 2019-07-22 02:18

You can use boolean indexing/mask -

N = 5            # Output array length
out = np.eye(N)  # Initialize output array with ones on diagonal

# Mask of upper triangular region except the diagonal region
range1 = np.arange(N)
mask = range1[:,None] < np.arange(N) 
# Or simply: mask = np.triu(np.ones((N,N)),1)==1

# Insert x1's at upper diagonal region (except the diagonal) and paste 
# transposed version of itself on lower diagonal region (including diagonal)
out[mask] = x1
out[~mask] = out.T[~mask]

Benchmarking

For the solutions posted so far and dealing with numpy arrays, here's a quick runtime test for the given inputs -

In [110]: %timeit triu_indices_based(x1,N)
10000 loops, best of 3: 19.9 µs per loop

In [111]: %timeit mask_based(x1,N)
100000 loops, best of 3: 6.88 µs per loop

With larger input array of x1 with 2001000 elements, here's the runtime results -

In [91]: %timeit mask_based(x1,N)
10 loops, best of 3: 34.9 ms per loop

In [92]: %timeit triu_indices_based(x1,N)
10 loops, best of 3: 80.9 ms per loop
查看更多
叛逆
3楼-- · 2019-07-22 02:20

I'm not sure if this is the formation rule you'd like, but you can do it with list comprehension:

x1 = np.array([0.9375, 0.75, 0.4375, 0.0, 0.9375, 0.75, 0.4375, 0.9375, 0.75, 0.9375])
x2 = [ [ x1[i-1-j] if j<i else x1[-i-1+j] for j in range(5) ] for i in range(5) ]
x2 = [ [ 1 if i==j else x2[i][j] for j in range(5) ] for i in range(5) ]
for el in x2:
    print el

gives me

[1, 0.9375, 0.75, 0.4375, 0.0]
[0.9375, 1, 0.9375, 0.75, 0.4375]
[0.75, 0.9375, 1, 0.9375, 0.75]
[0.4375, 0.75, 0.9375, 1, 0.9375]
[0.0, 0.4375, 0.75, 0.9375, 1]
查看更多
老娘就宠你
4楼-- · 2019-07-22 02:27

You can do:

x = np.ones((5, 5), dtype=float)
x[np.triu_indices(5, 1)] = x1        # sets the upper triangle
x[np.triu_indices(5, 1)[::-1]] = x1  # sets the lower triangle 

In the last line, the indices are reversed since your x1 is ordered for the upper triangle. You could also use x[np.tril_indices(5, -1)] = x1[::-1] if that feels more intuitive.

查看更多
登录 后发表回答