How to Transpose each element in a 3D np array - python

Given a 3D array a, I want to call np.tranpose on each of the element in its first index.
For example, given the array:
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],
[[3, 3, 3, 3],
[3, 3, 3, 3],
[3, 3, 3, 3]])
I want:
array([[[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]],
[[2, 2, 2],
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3],
[3, 3, 3]]])
Essentially I want to transpose each element inside the array. I tried to reshape it but I can't find a good way of doing it. Looping through it and calling transpose on each would be too slow. Any advice?

You can use the built-in numpy transpose method and directly specify the axes to transpose
>>> a = np.array([[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]],
[[2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2]],
[[3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3]]])
>>> print(a.transpose((0, 2, 1)))
[[[1 1 1]
[1 1 1]
[1 1 1]
[1 1 1]]
[[2 2 2]
[2 2 2]
[2 2 2]
[2 2 2]]
[[3 3 3]
[3 3 3]
[3 3 3]
[3 3 3]]]

Related

Split up numpy array

I've been looking all over but I'm not really sure how to even describe what it is I want. Essentially I need to turn
np.array(
[[0,0, 1,1, 2,2],
[0,0, 1,1, 2,2],
[3,3, 4,4, 5,5],
[3,3, 4,4, 5,5]]
)
into
np.array(
[[[0,1,2,3,4,5], [0,1,2,3,4,5]],
[[0,1,2,3,4,5], [0,1,2,3,4,5]]
)
I think I can accomplish that using np.reshape and maybe some other stuff but if I try reshape with arguments (2,2,6) I get back
[[[0 0 1 1 2 2]
[0 0 1 1 2 2]]
[[3 3 4 4 5 5]
[3 3 4 4 5 5]]]
which is not quite what I want.
Make your array with a couple of repeats:
In [208]: arr = np.arange(0,6).reshape(2,3)
In [209]: arr
Out[209]:
array([[0, 1, 2],
[3, 4, 5]])
In [210]: arr = arr.repeat(2,0).repeat(2,1)
In [211]: arr
Out[211]:
array([[0, 0, 1, 1, 2, 2],
[0, 0, 1, 1, 2, 2],
[3, 3, 4, 4, 5, 5],
[3, 3, 4, 4, 5, 5]])
Now break it into blocks which we can transpose:
In [215]: arr1 = arr.reshape(2,2,3,2)
In [216]: arr1
Out[216]:
array([[[[0, 0],
[1, 1],
[2, 2]],
[[0, 0],
[1, 1],
[2, 2]]],
[[[3, 3],
[4, 4],
[5, 5]],
[[3, 3],
[4, 4],
[5, 5]]]])
In [217]: arr1.shape
Out[217]: (2, 2, 3, 2)
In [218]: arr1.transpose(1,0,2,3)
Out[218]:
array([[[[0, 0],
[1, 1],
[2, 2]],
[[3, 3],
[4, 4],
[5, 5]]],
[[[0, 0],
[1, 1],
[2, 2]],
[[3, 3],
[4, 4],
[5, 5]]]])
Let's consolidate the middle 2 axes:
In [220]: arr1.transpose(1,0,2,3).reshape(2,6,2)
Out[220]:
array([[[0, 0],
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]],
[[0, 0],
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]]])
Almost there; just need another transpose:
In [221]: arr1.transpose(1,0,2,3).reshape(2,6,2).transpose(0,2,1)
Out[221]:
array([[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]],
[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]]])
The basic idea is to reshape the array into blocks, do a transpose, and reshape again. Here I needed another transpose, but if I choose the right one to start with I might not have needed that.
I don't know of a systematic way of doing this; there may be one, but so far I've just used a bit of trial and error when answering this kind of question. Everyone wants a different final arrangement.
This should work:
>>> import numpy as np
>>> A = np.array(
... [[0,0, 1,1, 2,2],
... [0,0, 1,1, 2,2],
... [3,3, 4,4, 5,5],
... [3,3, 4,4, 5,5]]
... )
>>> B = a[::2,::2].flatten()
>>> B
array([0, 1, 2, 3, 4, 5])
>>> C = np.tile(b, (2,2,1))
>>> C
array([[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]],
[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]]])
We can generalize this for a given n * m matrix, that contain blocks sized n/y * m/x of identical values (so there are y rows and x columns of blocks)
def transform(A, y, x):
dy = A.shape[0]/y
dx = A.shape[1]/x
B = A[::dy, ::dx].flatten()
return np.tile(B, (y,x,1))
I think this is what you are looking for:
import numpy
b=numpy.array([[0,0,1,1,2,2],[0,0,1,1,2,2],[3,3,4,4,5,5],[3,3,4,4,5,5]])
c1=(b[::2,::2].flatten(),b[::2,1::2].flatten())
c2=(b[1::2,::2].flatten(),b[1::2,1::2].flatten())
c=numpy.vstack((c1,c2)).reshape((2,2,6))
print(c)
which outputs:
[[[0 1 2 3 4 5]
[0 1 2 3 4 5]]
[[0 1 2 3 4 5]
[0 1 2 3 4 5]]]
and for general size target array and general size input array this is the algorithm with an example of 3*3 input array:
import numpy
b=numpy.array([[0,0,1,1,2,2],[0,0,1,1,2,2],[0,0,1,1,2,2],[3,3,4,4,5,5],[3,3,4,4,5,5],[3,3,4,4,5,5]])
(m,n)=b.shape
C=b[::int(m/2),::2].flatten(),b[::int(m/2),1::2].flatten()
for i in range(1,int(m/2)):
C=numpy.vstack((C,(b[i::int(m/2),::2].flatten(),b[i::int(m/2),1::2].flatten())))
print(C)
which outputs:
[[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]]

How can I tranpose arrays in a numpy matrix?

Similar to the premise in this question, I'd like to transpose each sub-array in the matrix. However, my sub-arrays are of different sizes. I've tried the following lines of code:
import numpy as np
test_array = np.array([
np.array([[1, 1, 1, 1],
[1, 1, 1, 1]]),
np.array([[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]]),
np.array([[3, 3],
[3, 3],
[3, 3]])
])
new_test_array = np.apply_along_axis(test_array, 0, np.transpose)
*** numpy.AxisError: axis 0 is out of bounds for array of dimension 0
new_test_array = np.transpose(test_array, (0, 2, 1))
*** ValueError: axes don't match array
new_test_array = np.array(list(map(np.transpose, test_array)))
returns original array
My expected output is
new_test_array = np.array([
np.array([[1, 1],
[1, 1],
[1, 1],
[1, 1]]),
np.array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]]),
np.array([[3, 3, 3],
[3, 3, 3]])
])
To answer shortly, you can do this on your data to get what you want:
new_test_array = [np.transpose(x) for x in test_array]
But in your example you build an array of lists instead of an array of varying sizes (which is impossible in numpy). It is also why your methods did not work.
So if you want to do it in a more correct way, first you have to use a list and then convert each list into a numpy array, which you can then transpose individually.
Here's an example code:
test_list = [[[1, 1, 1, 1],
[1, 1, 1, 1]],
[[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],
[[3, 3],
[3, 3],
[3, 3]]]
list_of_arrays = [np.array(x) for x in test_list]
transposed_arrays = [np.transpose(x) for x in list_of_arrays]
Printing transposed_arrays will give you this:
[array([[1, 1],
[1, 1],
[1, 1],
[1, 1]]),
array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]]),
array([[3, 3, 3],
[3, 3, 3]])]

Expanding a vector to a new size

Given a vector, for example
my_list=[1, 2, 3]
how to expand each entry to a new matrix (seen as a multidimensional list or, more likely, a numpy array)?
For example, in the case of matrix being a numpy array of size 2x2 matrix, the output, expanded_my_list, would be:
[[[1, 1], [1, 1]], [[2, 2], [2, 2]], [[3, 3], [3, 3]]]
or as a numpy array:
array([[[1, 1],
[1, 1]],
[[2, 2],
[2, 2]],
[[3, 3],
[3, 3]]])
where expanded_my_list.shape is (3,2,2).
One solution may be:
for i in range(len(my_list)):
expanded[:, i] = my_list[i].expand_as(matrix[:, i])
my_list = [1, 2, 3]
[[[e] * 2 for _ in range(2)] for e in my_list]
output:
[[[1, 1], [1, 1]], [[2, 2], [2, 2]], [[3, 3], [3, 3]]]
You could use numpy.tile().
By creating additional axis via np.newaxis and repeating the elements of the list along these axis you can create your wanted result:
import numpy as np
lst = [1, 2, 3]
arr = np.array(lst)
arr2 = np.tile(arr[:, np.newaxis, np.newaxis], reps=(1, 2, 2))
# Output:
# array([[[1, 1],
# [1, 1]],
# [[2, 2],
# [2, 2]],
# [[3, 3],
# [3, 3]]])
lst2 = arr2.tolist() # If a nested list is required
Or more general:
arr = np.array([[1, 2],
[3, 4]])
expanded_shape = (3, 4)
arr2 = np.tile(arr.reshape(arr.shape + (1,)*len(expanded_shape)),
reps=(1,)*arr.ndim + expanded_shape)
# Output, shape (2, 2, 3, 4)
# array([[[[1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]],
# [[2, 2, 2, 2],
# [2, 2, 2, 2],
# [2, 2, 2, 2]]],
# [[[3, 3, 3, 3],
# [3, 3, 3, 3],
# [3, 3, 3, 3]],
# [[4, 4, 4, 4],
# [4, 4, 4, 4],
# [4, 4, 4, 4]]]])

Python: extract the core of a 2D numpy array

Say I have a 2D numpy array like this:
In[1]: x
Out[1]:
array([[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4],
[5, 5, 5, 5, 5]], dtype=int64)
and I want to extract the (n-1)*(m-1) core, which would be:
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]], dtype=int64)
How could I do this, since the data structure is not flat? Do you suggest flattening it first?
This is a simplified version of a much bigger array, which core has dimension (n-33)*(n-33).
You can use negative stop indices to exclude the last x rows/columns and normal start indices:
>>> x[1:-1, 1:-1]
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]], dtype=int64)
For your new example:
>>> t = np.array([[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4],
[5, 5, 5, 5, 5]], dtype=np.int64)
>>> t[1:-1, 1:-1]
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4]], dtype=int64)
You could also remove 2 leading and trailing columns:
>>> t[1:-1, 2:-2]
array([[1],
[2],
[3],
[4]], dtype=int64)
or rows:
>>> t[2:-2, 1:-1]
array([[2, 2, 2],
[3, 3, 3]], dtype=int64)

How to add ones to matrix?

I have an array:
X = [[2, 2, 2],
[3, 3, 3],
[4, 4, 4]]
I need to add extra column in numpy array and fill it with ones using hstack and reshape. Like that:
X = [[2, 2, 2, 1],
[3, 3, 3, 1],
[4, 4, 4, 1]]
What I do:
X = np.hstack(X, np.ones(X.reshape(X, (2,3))))
And a get an error:
TypeError: only length-1 arrays can be converted to Python scalars
What's a problem? What I've done wrong?
Here's a couple ways with numpy.append, numpy.hstack or numpy.column_stack:
# numpy is imported as np
>>> x
array([[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
>>> np.append(x, np.ones([x.shape[0], 1], dtype=np.int32), axis=1)
array([[2, 2, 2, 1],
[3, 3, 3, 1],
[4, 4, 4, 1]])
>>> np.hstack([x, np.ones([x.shape[0], 1], dtype=np.int32)])
array([[2, 2, 2, 1],
[3, 3, 3, 1],
[4, 4, 4, 1]])
>>> np.column_stack([x, np.ones([x.shape[0], 1], dtype=np.int32)])
array([[2, 2, 2, 1],
[3, 3, 3, 1],
[4, 4, 4, 1]])
You can use numpy.insert():
>>> X
array([[2, 2, 2],
[3, 3, 3],
[4, 4, 4]])
Ones at the begining of matrix:
>>> X=np.insert(X,0,1.0,axis=1)
>>> X
array([[1, 2, 2, 2],
[1, 3, 3, 3],
[1, 4, 4, 4]])
Ones at the end of matrix
>>> X=np.insert(X,3,1.0,axis=1)
>>> X
array([[2, 2, 2, 1],
[3, 3, 3, 1],
[4, 4, 4, 1]])

Categories