2

Let's say that I have an array x = np.random.normal(size=(300, 300)) and that I wish to create a diagonal matrix of size (2, 2, 300, 300) using x. My first approach was to just do

import numpy as np

x = np.random.normal(size=(300, 300))

array = np.array([
    [x, 0.],
    [0., x]
])

However, when doing so I get an array of size (2, 2). Is there a numpy function for recasting the elements to the same size? Given that all the arrays of the list are the same shape, and that all other elements are floats.

Edit I might add that just defining an empty array and setting the diagonal to x is not a solution.

Edit 2 Here's a sample

import numpy as np


x = np.random.normal(size=(3, 3))

array = np.zeros((2, 2, *x.shape))

array[0, 0] = array[1, 1] = x

print(array)

Yielding

[[[[-1.57346701 -1.00813871 -0.72318135]
   [ 0.11852539  1.144298    1.38860739]
   [ 0.64571669  0.47474236  0.294049  ]]

  [[ 0.          0.          0.        ]
   [ 0.          0.          0.        ]
   [ 0.          0.          0.        ]]]


 [[[ 0.          0.          0.        ]
   [ 0.          0.          0.        ]
   [ 0.          0.          0.        ]]

  [[-1.57346701 -1.00813871 -0.72318135]
   [ 0.11852539  1.144298    1.38860739]
   [ 0.64571669  0.47474236  0.294049  ]]]]
2
  • 2
    Use a minimal sample like np.random.normal(size=(3, 3)) and show us the expected output? Commented Dec 4, 2017 at 19:20
  • Did either of the posted solutions work for you? Commented Dec 5, 2017 at 10:04

2 Answers 2

3

For the case of first two dimension of the output having lengths as 2, the posted solution with - array[0, 0] = array[1, 1] = x would be fast and readable.

I would try to solve for generic lengths.

Approach #1 : Here's one approach with masking -

m = 2 # length along first two axes of o/p
out = np.zeros((m,m) + x.shape)
out[np.eye(m,dtype=bool)] =  x

Approach #2 : Using assignment on first two axes merged view and thus avoiding the creation of any mask and leveraging fast sliced assignment -

out = np.zeros((m,m) + x.shape)
out.reshape((-1,) + x.shape)[::m+1] = x

Generic pattern case

We would leverage np.broadcast_to to solve for such a case -

def resizer(tup):
    shp = x.shape
    out_shp = (len(tup), -1) + shp
    list_arrs = [np.broadcast_to(j, shp) for i in tup for j in i]
    return np.asarray(list_arrs).reshape(out_shp)

Sample run -

In [121]: x
Out[121]: 
array([[55, 58, 75],
       [78, 78, 20],
       [94, 32, 47]])

In [122]: array0 = [
     ...:     [x, 0, 1, 2],
     ...:     [1, 2, 0, x]
     ...: ]

In [123]: resizer(array0)
Out[123]: 
array([[[[55, 58, 75],
         [78, 78, 20],
         [94, 32, 47]],

        [[ 0,  0,  0],
         [ 0,  0,  0],
         [ 0,  0,  0]],

        [[ 1,  1,  1],
         [ 1,  1,  1],
         [ 1,  1,  1]],

        [[ 2,  2,  2],
         [ 2,  2,  2],
         [ 2,  2,  2]]],
        .....

        [[55, 58, 75],
         [78, 78, 20],
         [94, 32, 47]]]])
Sign up to request clarification or add additional context in comments.

2 Comments

Very simple and elegant!
Thank you for this Divakar. As Max says, very simple and elegant (as always)
3

You can follow your first idea by:

x = np.random.normal(size=(300, 300))
O = np.zeros_like(x)
r = np.array([[x,O],[O,x]])

In [153]: r.shape
Out[153]: (2, 2, 300, 300)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.