Search code examples
pythonarraysnumpymultidimensional-arraydimensional-modeling

How to create a 4 dimensional numpy array from a 3 dimensional numpy array filling with zeros?


The problem

Create a higher dimensional NumPy array with zeros on the new dimensions

Details

Analyzing the last dimension, the result is similar to this:

(not an actual code, just a didactic example)

a.shape = (100,2,10) 
a[0,0,0]=1
a[0,0,1]=2  
...
a[0,0,9]=10

b.shape = (100,2,10,10)
b[0,0,0,:]=[0,0,0,0,0,0,0,0,0,1]
b[0,0,1,:]=[0,0,0,0,0,0,0,0,2,1] 
b[0,0,2,:]=[0,0,0,0,0,0,0,3,2,1]
...
b[0,0,2,:]=[10,9,8,7,6,5,4,3,2,1] 
    
a -> b 

The objective is to transform from a into b. The problem is that is not only filled with zeros but has a sequential composition with the original array.

Simpler problem for better understanding

Another way to visualize is using lower-dimensional arrays:

We have this:

a = [1,2]

And I want this:

b = [[0,1],[2,1]]

Using NumPy array and avoiding long for loops.

2d to 3d case

We have this:

a = [[1,2,3],[4,5,6],[7,8,9]]

And I want this:

b[0] = [[0,0,1],[0,2,1],[3,2,1]]
b[1] = [[0,0,4],[0,5,4],[6,5,4]]
b[2] = [[0,0,7],[0,8,7],[9,8,7]]

I feel that for the 4-dimensional problem only one for loop with 10 iterations is enough.


Solution

  • Try something like this in the framework of numpy:

    import numpy as np
    
    # create transformation tensors
    N = a.shape[-1]
    sigma1 = np.zeros((N,N,N))
    sigma2 = np.zeros((N,N,N))
    E = np.ones((N,N))
    for i in range(N):
       sigma1[...,i] = np.diag(np.diag(E,N-1-i),N-1-i)
       sigma2[N-1-i,N-1-i:,i] = 1
    
    b1 = np.tensordot(a, sigma1, axes=([-1],[0]))
    b2 = np.tensordot(a, sigma2, axes=([-1],[0]))
    

    where sigma1, sigma2 are the transformation tensors for which you can transform the data associated with the last dimension of a as you want (the two versions you mentioned in your question and comments). Here the loop is only used to create the transformation tensor.

    For a = [[1,2,3],[1,2,3],[1,2,3]], the first algorithm gives:

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

    and the last algorithm gives:

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

    Try to avoid lists and loops when using numpy as they slow down the execution speed.