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.