Python - Rearrange elements in a 3D array - python

I have the following Numpy array of shape (4, 4, 3):
a = [[[ 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]
[27 28 29]
[30 31 32]
[33 34 35]]
[[36 37 38]
[39 40 41]
[42 43 44]
[45 46 47]]]
I am looking for an elegant solution to re-arrange the elements in that array to get the following 3D array of shape (3, 4, 4):
a_new = [[[ 0 3 6 9]
[12 15 18 21]
[24 27 30 33]
[36 39 42 45]]
[[ 1 4 7 10]
[13 16 19 22]
[25 28 31 34]
[37 40 43 46]]
[[ 2 5 8 11]
[14 17 20 23]
[26 29 32 35]
[38 41 44 47]]]

Use np.transpose -
a.transpose(2,0,1)
Or use np.rollaxis -
np.rollaxis(a,2,0) # Or np.rollaxis(a,-1,0)

In case somebody asks the same question for pure Python:
mylist = [[[1,2,3], [4,5,6]], [[7,8,9], [10, 11, 12]]]
flat = sum(sum(mylist, []), [])
groups = 3
print [flat[r::groups] for r in range(groups)]
[[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]

The fastest way I can think of is to use numpy's swapaxes function in combination with the transpose function.
anew=np.swapaxes(a,0,1).T

Related

How can I append difference dim' array?

I made some numpy array np3
np1 = np.array(range(2*3*5))
np3 = np1.reshape(2,3,5)
and np3 has shape like this:
[[[ 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 27 28 29]]]
then, I made new numpy array np_55
np_55 = np.full((3,1),55)
and np_55 has shape like this:
[[55]
[55]
[55]]
I want make numpy array like below using both numpy arrays np3 and np_55 (I'll call that 'ANSWER'):
[[[ 0 1 2 3 4 55]
[ 5 6 7 8 9 55]
[10 11 12 13 14 55]]
[[15 16 17 18 19 55]
[20 21 22 23 24 55]
[25 26 27 28 29 55]]]
but I can't make it using both numpy arrays np3 and np_55. Of course I can make hard code like this:
a = np.append((np3[0]), np3_55, axis=1)
b = np.append((np3[1]), np3_55, axis=1)
a = a.reshape(1,3,6)
b = b.reshape(1,3,6)
np.append(a, b, axis=0)
but I don't know how can I solve ANSWER simply.
You can try the following:
import numpy as np
a = np.arange(2*3*5).reshape(2, 3, 5)
b = np.full((3,1),55)
np.c_[a, np.broadcast_to(b, (a.shape[0], *b.shape))]
It gives:
array([[[ 0, 1, 2, 3, 4, 55],
[ 5, 6, 7, 8, 9, 55],
[10, 11, 12, 13, 14, 55]],
[[15, 16, 17, 18, 19, 55],
[20, 21, 22, 23, 24, 55],
[25, 26, 27, 28, 29, 55]]])

Vectorized method to compute Hankel matrix for multi-input, multi-output data sequence

I'm constructing a Hankel matrix and wondered if there's a way to further vectorize the following computation (i.e. without for loops or list comprehensions).
# Imagine this is some time-series data
q = 2 # Number of inputs
p = 2 # Number of outputs
nt = 6 # Number of timesteps
y = np.array(range(p*q*nt)).reshape([nt, p, q]).transpose()
assert y.shape == (q, p, nt)
print(y.shape)
(2, 2, 6)
print(y[:,:,0])
[[0 2]
[1 3]]
print(y[:,:,1])
[[4 6]
[5 7]]
print(y[:,:,2])
[[ 8 10]
[ 9 11]]
Desired results
# Desired Hankel matrix
m = n = 3 # dimensions
assert nt >= m + n
h = np.zeros((q*m, p*n), dtype=int)
for i in range(m):
for j in range(n):
h[q*i:q*(i+1), p*j:p*(j+1)] = y[:, :, i+j]
print(h)
[[ 0 2 4 6 8 10]
[ 1 3 5 7 9 11]
[ 4 6 8 10 12 14]
[ 5 7 9 11 13 15]
[ 8 10 12 14 16 18]
[ 9 11 13 15 17 19]]
(Note how the 2x2 blocks are stacked)
# Alternative method using stacking
b = np.hstack([y[:,:,i] for i in range(y.shape[2])])
assert b.shape == (q, p*nt)
print(b)
[[ 0 2 4 6 8 10 12 14 16 18 20 22]
[ 1 3 5 7 9 11 13 15 17 19 21 23]]
h = np.vstack([b[:, i*p:i*p+n*q] for i in range(m)])
print(h)
[[ 0 2 4 6 8 10]
[ 1 3 5 7 9 11]
[ 4 6 8 10 12 14]
[ 5 7 9 11 13 15]
[ 8 10 12 14 16 18]
[ 9 11 13 15 17 19]]
You can use stride_tricks:
>>> from numpy.lib.stride_tricks import as_strided
>>>
>>> a = np.arange(20).reshape(5,2,2)
>>> s0,s1,s2 = a.strides
>>> as_strided(a,(3,2,3,2),(s0,s2,s0,s1)).reshape(6,6)
array([[ 0, 2, 4, 6, 8, 10],
[ 1, 3, 5, 7, 9, 11],
[ 4, 6, 8, 10, 12, 14],
[ 5, 7, 9, 11, 13, 15],
[ 8, 10, 12, 14, 16, 18],
[ 9, 11, 13, 15, 17, 19]])

Reshape and indexing in MATLAB and Python

I have a code in Matlab which I need to translate in Python. A point here that shapes and indexes are really important since it works with tensors. I'm a little bit confused since it seems that it's enough to use order='F' in python reshape(). But when I work with 3D data I noticed that it does not work. For example, if A is an array from 1 to 27 in python
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]]])
if I perform A.reshape(3, 9, order='F') I get
[[ 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]]
In Matlab for A = 1:27 reshaped to [3, 3, 3] and then to [3, 9] it seems that I get another array:
1 4 7 10 13 16 19 22 25
2 5 8 11 14 17 20 23 26
3 6 9 12 15 18 21 24 27
And SVD in Matlab and Python gives different results. So, is there a way to fix this?
And maybe you know the correct way of operating with multidimensional arrays in Matlab -> python, like should I get the same SVD for arrays like arange(1, 13).reshape(3, 4) and in Matlab 1:12 -> reshape(_, [3, 4]) or what is the correct way to work with that? Maybe I can swap axes somehow in python to get the same results as in Matlab? Or change the order of axes in reshape(x1, x2, x3,...) in Python?
I was having the same issues, until I found this wikipedia article: row- and column-major order
Python (and C) organizes the data arrays in row major order. As you can see in your first example code, the elements first increases with the columns:
array([[[ 1, 2, 3],
- - - -> increasing
Then in the rows
array([[[ 1, 2, 3],
[ 4, <--- new element
When all columns and rows are full, it moves to the next page.
array([[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[10, <-- new element in next page
In matlab (as fortran) increases first the rows, then the columns, and so on.
For N-dimensionals arrays it looks like:
Python (row major -> last dimension is contiguous): [dim1,dim2,...,dimN]
Matlab (column major -> first dimension is contiguous): the same tensor in memory would look the other way around .. [dimN,...,dim2,dim1]
If you want to export n-dim. arrays from python to matlab, the easiest way is to permute the dimensions first:
(in python)
import numpy as np
import scipy.io as sio
A=np.reshape(range(1,28),[3,3,3])
sio.savemat('A',{'A':A})
(in matlab)
load('A.mat')
A=permute(A,[3 2 1]);%dimensions in reverse ordering
reshape(A,9,3)' %gives the same result as A.reshape([3,9]) in python
Just notice that the (9,3) an the (3,9) are intentionally putted in reverse order.
In Matlab
A = 1:27;
A = reshape(A,3,3,3);
B = reshape(A,9,3)'
B =
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
size(B)
ans =
3 9
In Python
A = np.array(range(1,28))
A = A.reshape(3,3,3)
B = A.reshape(3,9)
B
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]])
np.shape(B)
(3, 9)

numpy submatrix 3D using a single indexing item

I have a 3D numpy array:
K = (np.arange(36)).reshape((4,3,3))+1
[[[ 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]]]
where each item in K is a matrix.
Now, I want to get all 2D submatrix using a certain index vector
I know that it is possible in this way:
idx = np.s_[:,:2,:2]
K_sub = K[idx]
[[[ 1 2]
[ 4 5]]
[[10 11]
[13 14]]
[[19 20]
[22 23]]
[[28 29]
[31 32]]]
The problem is that I want to use an arbitrary indexing array and not slicing to select rows and cols.
Moreover, I want to use a single object to get the list of submatrices, something like:
K_sub = [magic_indexing]
and not:
K_sub = np.array([k_[train][:,train] for k_ in K])
Exists a simple way to do it?
Not sure if it's simply enough for you, but one way would be with np.ix_ and thus uses advanced-indexing, like so -
K[np.ix_(np.arange(K.shape[0]), train, train)]

Python - Convert a list to a list of lists

I'm trying to create a list of lists, such that each inner list has 8 elements, in a python one-liner.
So far I have the following:
locations = [[alphabet.index(j) for j in test]]
That maps to one big list inside of a list:
[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]]
But I want to split it up to be multiple inner lists, each 8 elements:
[[1,2,3,4,5,6,7,8],[9,10,11,12,13,14,15,16]]
Any idea how I can acheive this?
Use list slicing with range() to get the starting indexes:
In [3]: test = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
In [4]: [test[i:i+8] for i in range(0, len(test), 8)]
Out[4]: [[1, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]]
As a function:
In [7]: def slicing(list_, elem_):
...: return [list_[i:i+elem_] for i in range(0, len(list_), elem_)]
In [8]: slicing(test, 8)
Out[8]: [[1, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]]
Another solution could be to use NumPy
import numpy as np
data = [x for x in xrange(0, 64)]
data_split = np.array_split(np.asarray(data), 8)
Output:
for a in data_split:
print a
[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 27 28 29 30 31]
[32 33 34 35 36 37 38 39]
[40 41 42 43 44 45 46 47]
[48 49 50 51 52 53 54 55]
[56 57 58 59 60 61 62 63]

Categories

Resources