Home > Net >  Reshape a 3d array to a 2d array with leading points
Reshape a 3d array to a 2d array with leading points

Time:01-25

I want to reshape this array (Python)

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

To this:

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

And then back

Couldn't figure out how to do it with np.reshape

Its a series of height maps, and I want to interpolate each point with the corresponding one at the next map to create a smooth transition between them

CodePudding user response:

With last correction, it seems that what you want is something like

np.moveaxis(a, 0,-1).reshape(-1,3)

Result

array([[0, 0, 0],
       [1, 1, 1],
       [2, 2, 2],
       [3, 3, 3],
       [4, 4, 4],
       [5, 5, 5],
       [6, 6, 6],
       [7, 7, 7],
       [8, 8, 8]])

You probably know how to use reshape. It reinterprets the data as an array of as many lines as needed and 3 columns. The reason why reshape alone won't do exactly what you want is because you would need the 0s to be consecutive in memory, then the 1s then the 2s, ... Which they are not. But that is solved by moveaxis: those 0s, 1s, 2s, ... are consecutive when you iterate along axis 0 of your input array. So all you have to do is move axis 0 to the end, so that iterating the last axis does that (visiting 0s, then 1s, then 2s, ...).

Note that moveaxis is very fast. Because it does not really build a new array. It is just a different view of the existing array. Some tricks with strides, so that visiting order appears changed.

Since you also asked for the other way, here it is (but it is just the same 2 operations, reversed and in reverse order. So undo the reshape, then undo the move axis)

res=np.moveaxis(a, 0,-1).reshape(-1,3) # Just to start from here
np.moveaxis(res.reshape(-1,3,3), -1, 0)

Result

array([[[0, 1, 2],
        [3, 4, 5],
        [6, 7, 8]],

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

       [[0, 1, 2],
        [3, 4, 5],
        [6, 7, 8]]])

as expected

CodePudding user response:

You can do via list comprehension as well with itertools chain as stated by @Unmitigated

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

from itertools import chain as c
[list(x) for x in zip(*(c(*y) for y in l))]
[[0, 0, 0],
 [1, 1, 1],
 [2, 2, 2],
 [3, 3, 3],
 [4, 4, 4],
 [5, 5, 5],
 [6, 6, 6],
 [7, 7, 7],
 [8, 8, 8]]

CodePudding user response:

import numpy as np
a = np.array(
    [[[0, 1, 2], [3, 4, 5], [6, 7, 8]],
     [[0, 1, 2], [3, 4, 5], [6, 7, 8]],
     [[0, 1, 2], [3, 4, 5], [6, 7, 8]]]
)
b = np.vstack(np.moveaxis(a, 0, 2))

Reverse operation:

a2 = np.moveaxis(np.vsplit(b, 3), 2, 0)

I think the easiest way to understand how this works is to look at the examples for vstack and then figuring out how do we need to modify array a so that vstack can produce the desired output.

In this case,

>>> np.moveaxis(a, 0, 2)
array([[[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]],

       [[4, 4, 4],
        [5, 5, 5],
        [6, 6, 6]],

       [[7, 7, 7],
        [8, 8, 8],
        [9, 9, 9]]])

prepares the array a in such a way that now vstack can simply "stack" (glue? concatenate?) the 3 "sub-arrays" on top of each other, producing the desired 2D array.

  • Related