Transposing arrays in an array - python

I have a 2D array of shape (M*N,N) which in fact consists of M, N*N arrays. I would like to transpose all of these elements(N*N matrices) in a vectorized fashion. As an example,
import numpy as np
A=np.arange(1,28).reshape((9,3))
print "A before transposing:\n", A
for i in range(3):
A[i*3:(i+1)*3,:]=A[i*3:(i+1)*3,:].T
print "A after transposing:\n", A
This code generates the following output:
A before transposing:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]
[13 14 15]
[16 17 18]
[19 20 21]
[22 23 24]
[25 26 27]]
A after transposing:
[[ 1 4 7]
[ 2 5 8]
[ 3 6 9]
[10 13 16]
[11 14 17]
[12 15 18]
[19 22 25]
[20 23 26]
[21 24 27]]
Which I expect. But I want the vectorized version.

Here's a nasty way to do it in one line!
A.reshape((-1, 3, 3)).swapaxes(-1, 1).reshape(A.shape)
Step by step. Reshape to (3, 3, 3)
>>> A.reshape((-1, 3, 3))
array([[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]]])
Then perform a transpose-like operation swapaxes on each sub-array
>>> A.reshape((-1, 3, 3)).swapaxes(-1, 1)
array([[[ 1, 4, 7],
[ 2, 5, 8],
[ 3, 6, 9]],
[[10, 13, 16],
[11, 14, 17],
[12, 15, 18]],
[[19, 22, 25],
[20, 23, 26],
[21, 24, 27]]])
Finally reshape to (9, 3).
>>> A.reshape((-1, 3, 3)).swapaxes(-1, 1).reshape(A.shape)
array([[ 1, 4, 7],
[ 2, 5, 8],
[ 3, 6, 9],
[10, 13, 16],
[11, 14, 17],
[12, 15, 18],
[19, 22, 25],
[20, 23, 26],
[21, 24, 27]])
>>>
I think that with any method, data must be copied since there's no 2d strides/shape that can generate the result from:
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27])
(is there?) In my version I think data is copied in the final reshape step

In [42]: x = np.arange(1,28).reshape((9,3))
In [43]: x
Out[43]:
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12],
[13, 14, 15],
[16, 17, 18],
[19, 20, 21],
[22, 23, 24],
[25, 26, 27]])
In [31]: r,c = x.shape
In [39]: z = np.vstack(np.hsplit(x.T,r/c))
In [45]: z
Out[45]:
array([[ 1, 4, 7],
[ 2, 5, 8],
[ 3, 6, 9],
[10, 13, 16],
[11, 14, 17],
[12, 15, 18],
[19, 22, 25],
[20, 23, 26],
[21, 24, 27]])

Related

Forming an array with elements in specific positions from multiple arrays in Python

I have an array A. I want to take the first, second,...,ninth elements of each A[0],A[1],A[2] to form a new array B. I present the current and expected outputs.
import numpy as np
A=np.array([np.array([[1, 2, 3],
[4, 5, 6 ],
[7, 8, 9]]),
np.array([[[10, 11, 12],
[13, 14, 15 ],
[16, 17, 18]]]),
np.array([[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]]])], dtype=object)
for t in range(0,len(A)):
B=A[0][t][0]
print([B])
The current output is
[1]
[4]
[7]
The expected output is
array([[1,10,19],
[2,11,20],
[3,12,21],
[4,13,22],
[5,14,23],
[6,15,24],
[7,16,25],
[8,17,26],
[9,18,27]])
You can traverse the array, append all values as columns and transpose the resulting matrix:
import numpy as np
A=np.array([np.array([[1, 2, 3],
[4, 5, 6 ],
[7, 8, 9]]),
np.array([[[10, 11, 12],
[13, 14, 15 ],
[16, 17, 18]]]),
np.array([[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]]])], dtype=object)
out = np.array([A[i].flatten() for i in range(len(A))]).transpose()
#out = np.array([i.flatten() for i in A]).transpose() #Second option
print(out)
Output:
[[ 1 10 19]
[ 2 11 20]
[ 3 12 21]
[ 4 13 22]
[ 5 14 23]
[ 6 15 24]
[ 7 16 25]
[ 8 17 26]
[ 9 18 27]]
B = np.array([a.ravel() for a in A]).T
#array([[ 1, 10, 19],
# [ 2, 11, 20],
# [ 3, 12, 21],
# [ 4, 13, 22],
# [ 5, 14, 23],
# [ 6, 15, 24],
# [ 7, 16, 25],
# [ 8, 17, 26],
# [ 9, 18, 27]])
Your array is broken.
If you fix it, you can deal with it a lot easier. .squeeze() shakes useless dimensions out of a numpy array.
numpy lets you transpose dimensions.
ravel flattens an array. That's a valid approach but I've chosen to do the flattening using reshape
a1 = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
a2 = np.array([[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]])
a3 = np.array([[[19, 20, 21],
[22, 23, 24],
[25, 26, 27]]])
A = [a1, a2, a3]
print([a.shape for a in A])
# [(3, 3), (1, 3, 3), (1, 3, 3)]
A = [a.squeeze() for a in A]
print([a.shape for a in A])
# [(3, 3), (3, 3), (3, 3)]
A = np.array(A)
print(repr(A))
# array([[[ 1, 2, 3],
# [ 4, 5, 6],
# [ 7, 8, 9]],
#
# [[10, 11, 12],
# [13, 14, 15],
# [16, 17, 18]],
#
# [[19, 20, 21],
# [22, 23, 24],
# [25, 26, 27]]])
A.transpose((1, 2, 0)) # explicit form of A.transpose()
# array([[[ 1, 10, 19],
# [ 2, 11, 20],
# [ 3, 12, 21]],
#
# [[ 4, 13, 22],
# [ 5, 14, 23],
# [ 6, 15, 24]],
#
# [[ 7, 16, 25],
# [ 8, 17, 26],
# [ 9, 18, 27]]])
A.transpose((1, 2, 0)).reshape((-1, 3))
# array([[ 1, 10, 19],
# [ 2, 11, 20],
# [ 3, 12, 21],
# [ 4, 13, 22],
# [ 5, 14, 23],
# [ 6, 15, 24],
# [ 7, 16, 25],
# [ 8, 17, 26],
# [ 9, 18, 27]])

How to split a numpy array into overlapping tiles?

How can I convert the a array into the b array as they are specified below in Python and using numpy library? I am looking for a very efficient way since my actual array that I want to use this method on is very big. I should mention that the numbers can be any number and there is no relationship among the numbers. Also, I tried to show in the below picture how I want to slice the array.
import numpy as np
a = np.arange(1, 49).reshape(6, 8)
a = [[ 1, 2, 3, 4, 5, 6, 7, 8],
[ 9, 10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30, 31, 32],
[33, 34, 35, 36, 37, 38, 39, 40],
[41, 42, 43, 44, 45, 46, 47, 48]]
b =[[1, 2, 9, 10], [2, 3, 10, 11], [3, 4, 11, 12], [4, 5, 12, 13],
[5, 6, 13, 14], [6, 7, 14, 15], [7, 8, 15, 16], [9, 10, 17, 18],
[10, 11, 18, 19], [11, 12, 19, 20], [12, 13, 20, 21], [13, 14, 21, 22],
[14, 15, 22, 23], [15, 16, 23, 24], [17, 18, 25, 26], [18, 19, 26, 27],
[19, 20, 27, 28], [20, 21, 28, 29], [21, 22, 29, 30], [22, 23, 30, 31],
[23, 24, 31, 32], [25, 26, 33, 34], [26, 27, 34, 35], [27, 28, 35, 36],
[28, 29, 36, 37], [29, 30, 37, 38], [30, 31, 38, 39], [31, 32, 39, 40],
[33, 34, 41, 42], [34, 35, 42, 43], [35, 36, 43, 44], [36, 37, 44, 45],
[37, 38, 45, 46], [38, 39, 46, 47], [39, 40, 47, 48]]
I was trying to find a way with reshape and transpose function but the problem is that I could not find a way to include the boundaries. c shows what I was thinking about the solution.
c = a.reshape(3, 2, 4, 2).transpose(0, 2, 3, 1).reshape(3*4, 2*2).
The picture: https://ibb.co/QC7tkPM.
With numpy 1.20 or higher you can use np.lib.stride_tricks.sliding_window_view:
import numpy as np
a = np.arange(12).reshape(3, 4)
print(a)
Gives:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
Below (2,2) is the shape of the sliding window:
windows = np.lib.stride_tricks.sliding_window_view(a, (2,2))
print(windows)
It gives:
[[[[ 0 1]
[ 4 5]]
[[ 1 2]
[ 5 6]]
[[ 2 3]
[ 6 7]]]
[[[ 4 5]
[ 8 9]]
[[ 5 6]
[ 9 10]]
[[ 6 7]
[10 11]]]]
In earlier versions of numpy a similar result can be obtained using np.lib.index_tricks.as_strided:
w = 2 # width and height of the sliding window
r, c = a.shape
size = a.itemsize
ast = np.lib.index_tricks.as_strided
windows_ast = ast(a,
shape=(r - w + 1, c - w + 1, w, w),
strides=(c * size, size, c * size, size))
print(windows_ast)
It gives:
[[[[ 0 1]
[ 4 5]]
[[ 1 2]
[ 5 6]]
[[ 2 3]
[ 6 7]]]
[[[ 4 5]
[ 8 9]]
[[ 5 6]
[ 9 10]]
[[ 6 7]
[10 11]]]]
Note that the numpy documentation warns that np.lib.stride_tricks.as_strided should be avoided if possible, since its results may lead to several issues. The above code may also fail if the input array does not have a contiguous memory layout.
In any case, you can reshape the result to the desired shape:
windows.reshape(-1, 4)
It gives:
array([[ 0, 1, 4, 5],
[ 1, 2, 5, 6],
[ 2, 3, 6, 7],
[ 4, 5, 8, 9],
[ 5, 6, 9, 10],
[ 6, 7, 10, 11]])
Thank you all for your solutions and insights. It just gave me a reason to update my numpy to 1.21.2. The reshape/transpose combo also can work when we are willing to repeat the rows and columns at the boundaries using np.repeat. However, it would be more costly than np.lib.stride_tricks.sliding_window_view. Here is an example:
a = np.arange(1,49).reshape(6,8)
aa = np.repeat(a, repeats=[1,2,2,2,2,1], axis=0)
aa = np.repeat(aa, repeats=[1,2,2,2,2,2,2,1], axis=1)
b = aa.reshape(5,2,7,2).transpose(0,2,3,1).reshape(5*7,2*2)

Reshaping a numpy array into desired shape

I am working in numpy and have a numpy array of the form;
[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12],
[13, 14, 15],
[16, 17, 18],
[19, 20, 21],
[22, 23, 24]]
I want to use only the reshape and transpose functions and obtain the following array:
[[ 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 21],
[ 4, 5, 6, 10, 11, 12, 16, 17, 18, 22, 23, 24]]
Can this be done? I have spent hours trying and am starting to think it just can't be done - am I missing something obvious?
You can reshape into columns, then transpose, then reshape with something like:
a = np.array([[ 1,2,3],
[ 4,5,6],
[ 7,8,9],
[10, 11, 12],
[13, 14, 15],
[16, 17, 18],
[19, 20, 21],
[22, 23, 24]])
a.reshape(-1, 2, 3).transpose((1, 0, 2)).reshape(2, -1)
# array([[ 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 21],
# [ 4, 5, 6, 10, 11, 12, 16, 17, 18, 22, 23, 24]])
You may try to slice odd and even and pass them to np.reshape.
a_out = np.reshape([a[::2], a[1::2]], (2,-1))
Out[81]:
array([[ 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 21],
[ 4, 5, 6, 10, 11, 12, 16, 17, 18, 22, 23, 24]])

Sum array elements vertically with iteration

Hi I have an array that I want to sum the elements vertically. Just wonder are there any functions can do this easily ?
a = [[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]]
I want to print the answers of 1+6+11+16+21 , 2+7+12+17, 3+8+13, 4+9, 5
As you can see, in each iteration, there is one element less.
This is one approach using zip and a simple iteration.
Ex:
a = [[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]]
print([sum(v[:-i]) if i else sum(v) for i, v in enumerate(zip(*a))])
Output:
[55, 38, 24, 13, 5]
Converting to a numpy array, and then using the following list comprehension
a = np.array(a)
[a[:5-i,i].sum() for i in range(5)]
yields the following:
[55, 38, 24, 13, 5]

Convert Numpy array of square arrays to numpy square array, conserving "layout"

First time i ask something here. I am kind of 'blocked'.
I have an array composed of n x n arrays (lets take n=3 for simplification):
[
[
[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]
],
[
[9, 10, 11],
[12, 13, 14],
[15, 16, 17]
],
[
[18, 19, 20],
[21, 22, 23],
[24, 25, 26]
]
]
(altho my array contains a lot more than 3 3*3 arrays)
i want to achieve a 2D array like this :
[0,1,2,9,10,11,18,19,20]
[3,4,5,12,13,14,21,22,23]
[6,7,8,15,16,17,24,25,26]
Is there a trick i haven't thought of because i cant think of any way to accomplish the transformation.
Thanks
Slightly cleaner than moveaxis maybe:
import numpy as np
a = np.arange(27).reshape(3,3,3)
a.swapaxes(0,1).reshape(3,-1)
array([[ 0, 1, 2, 9, 10, 11, 18, 19, 20],
[ 3, 4, 5, 12, 13, 14, 21, 22, 23],
[ 6, 7, 8, 15, 16, 17, 24, 25, 26]])
Think of this as a list of 3 arrays, that you want to join horizontally:
In [171]: arr = np.arange(27).reshape(3,3,3)
In [172]: np.hstack(arr)
Out[172]:
array([[ 0, 1, 2, 9, 10, 11, 18, 19, 20],
[ 3, 4, 5, 12, 13, 14, 21, 22, 23],
[ 6, 7, 8, 15, 16, 17, 24, 25, 26]])
In [173]: arr
Out[173]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[18, 19, 20],
[21, 22, 23],
[24, 25, 26]]])
Of I like to test ideas with arrays with differing dimensions. Then the various axis manipulations becomes more obvious.
In [174]: arr = np.arange(24).reshape(2,3,4)
In [175]: arr
Out[175]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
In [176]: np.hstack(arr)
Out[176]:
array([[ 0, 1, 2, 3, 12, 13, 14, 15],
[ 4, 5, 6, 7, 16, 17, 18, 19],
[ 8, 9, 10, 11, 20, 21, 22, 23]])
In [177]: np.vstack(arr)
Out[177]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
But there's nothing wrong with the variations on the transpose and reshape answers, if starting from a 3d array (as opposed to a list of arrays):
In [187]: arr.transpose(1,0,2).reshape(3,-1)
Out[187]:
array([[ 0, 1, 2, 9, 10, 11, 18, 19, 20],
[ 3, 4, 5, 12, 13, 14, 21, 22, 23],
[ 6, 7, 8, 15, 16, 17, 24, 25, 26]])
You could use np.block
>>> import numpy as np
>>> X = np.arange(27).reshape(3, 3, 3)
>>>
>>> np.block(list(X))
array([[ 0, 1, 2, 9, 10, 11, 18, 19, 20],
[ 3, 4, 5, 12, 13, 14, 21, 22, 23],
[ 6, 7, 8, 15, 16, 17, 24, 25, 26]])
A simple reshape doesn't suffice since you have to change the order of the axes first:
import numpy as np
a = np.array([[[0,1,2],[3,4,5],[6,7,8]],[[9,10,11],[12,13,14],[15,16,17]],[[18,19,20],[21,22,23],[24,25,26]]])
np.moveaxis(a, 0, 1).reshape(3,9)
[[ 0 1 2 9 10 11 18 19 20]
[ 3 4 5 12 13 14 21 22 23]
[ 6 7 8 15 16 17 24 25 26]]

Categories

Resources