numpy 3d array and 1d array addition on first axis - python

i have a 1d np array "array1d" and a 3d np array "array3d", i want to sum them so the n'th value in "array1d" will be added to each of the elements of the n'th plane in array3d.
this can be done in the following loop
for i, value in enumerate(array1d):
array3d[i] += value
question is, how can this be done in a single numpy line?
example arrays:
arr1d = np.array(range(3))
>>>array([0, 1, 2])
arr3d = np.array(range(27)).reshape(3, 3, 3)
>>>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]]])
wanted result:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])

Use Numpy's broadcasting features:
In [23]: arr1d[:, None, None] + arr3d
Out[23]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])
This basically copies the content of arr1d across the other two dimensions (without actually copying, it just provides a view of the memory which looks like it). Instead of None, you can also use numpy.newaxis.
Alternatively, you can also use reshape:
In [32]: arr1d.reshape(3, 1, 1) + arr3d
Out[32]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])

Related

Use .take() to index multidimensional array

I have a multidimensional array of shape (n,x,y). For this example can use this array
A = 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],
[27, 28, 29],
[30, 31, 32],
[33, 34, 35]]])
I then have another multidimensional array that has index values that I want to use on the original array, A. This has shape (z,2) and the values represent row values index’s
Row_values = array([[0,1],
[0,2],
[1,2],
[1,3]])
So I want to use all the index values in row_values to apply to each of the three arrays in A so I end up with a final array of shape (12,2,3)
Result = ([[[0,1,2],
[3,4,5]],
[[0,1,2],
[6,7,8]],
[[3,4,5],
[6,7,8]]
[[3,4,5],
[9,10,11],
[[12,13,14],
[15,16,17]],
[[12,13,14],
[18,19,20]],
[[15,16,17],
[18,19,20]],
[[15,16,17],
[21,22,23]],
[[24,25,26],
[27,28,29]],
[[24,25,26],
[30,31,32]],
[[27,28,29],
[30,31,32]],
[[27,28,29],
[33,34,35]]]
I have tried using np.take() but haven’t been able to make it work. Not sure if there’s another numpy function that is easier to use
We can advantage of NumPy's advanced indexing and using np.repeat and np.tile along with it.
cidx = np.tile(Row_values, (A.shape[0], 1))
ridx = np.repeat(np.arange(A.shape[0]), Row_values.shape[0])
out = A[ridx[:, None], cidx]
# out.shape -> (12, 2, 3)
Using np.take
np.take(A, Row_values, axis=1).reshape((-1, 2, 3))
# Or
A[:, Row_values].reshape((-1, 2, 3))
Output:
array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 0, 1, 2],
[ 6, 7, 8]],
[[ 3, 4, 5],
[ 6, 7, 8]],
[[ 3, 4, 5],
[ 9, 10, 11]],
[[12, 13, 14],
[15, 16, 17]],
[[12, 13, 14],
[18, 19, 20]],
[[15, 16, 17],
[18, 19, 20]],
[[15, 16, 17],
[21, 22, 23]],
[[24, 25, 26],
[27, 28, 29]],
[[24, 25, 26],
[30, 31, 32]],
[[27, 28, 29],
[30, 31, 32]],
[[27, 28, 29],
[33, 34, 35]]])

How does np.argmax(axis=0) work on 3D arrays?

I am stuck at, as to how does np.argmax(arr, axis=0) work? I know how np.argmax(axis=0) works on 2D arrays. But this 3D one has really confused me.
My Code:
arr = 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]],
[[25, 26, 27],
[28, 29, 30],
[31, 32, 33],
[34, 35, 36]]])
Operation:
np.argmax(arr, axis = 0)
Output:
array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]], dtype=int64)
FYI - I do know how np.argmax(axis=0) works on 2D arrays. But this 3D one has really confused me.
You need to understand better what is axis=0 here. It can be interpreted as height level of rectangle. So your output shows different levels of that rectangle:
level 0 level 1 level 2
[ 1, 2, 3] [13, 14, 15] [16, 17, 18]
[ 4, 5, 6] [16, 17, 18] [19, 20, 21]
[ 7, 8, 9] [19, 20, 21] [22, 23, 24]
[10, 11, 12] [22, 23, 24] [25, 16, 27]
Then argmax describes indices of levels at which max values are attained. They are:
[16, 17, 18]
[19, 20, 21]
[22, 23, 24]
[25, 16, 27]
It's definitely the upmost level (number 2) for any of these cells
so argmax of every cell is assigned to 2.

How to subset a numpy array of different lengths

I have a numpy array and would like to subset the first two arrays of each element in an ndarray.
Here is an example array:
import numpy as np
a1 = np.array([[ 1, 2, 3],
[ 4, 5, 6]])
a2 = np.array([[ 7, 8, 9],
[10, 11, 12],
[13, 14, 15],
[16, 17, 18]])
a3 = np.array([[19, 20, 21],
[22, 23, 24],
[25, 26, 27]])
A = np.array([a1, a2, a3])
print("A =\n", A)
Which prints:
A =
[array([[ 1, 2, 3],
[ 4, 5, 6]])
array([[ 7, 8, 9],
[10, 11, 12],
[13, 14, 15],
[16, 17, 18]])
array([[19, 20, 21],
[22, 23, 24],
[25, 26, 27]])]
The desired result is as follows:
A =
[array([[ 1, 2, 3],
[ 4, 5, 6]])
array([[ 7, 8, 9],
[10, 11, 12]])
array([[19, 20, 21],
[22, 23, 24]])]
To print the equivalent object, you could do
print(np.array([a1[0:2], a2[0:2], a3[0:2]]))
But I want to directly get what is desired using A.
What is the correct way of doing this in numpy?
Edit: I would like to subset the array without looping. Alternative ways of structuring the arrays so that they can be directly indexed are okay too. Any numpy function to avoid looping is fair game.
a = [i[0:2] for i in A]
This will work!

Rearranging 3D numpy arrays in a specific manner

I'm working with 3D matrices in numpy. I'm actually passing these matrices to C using ctypes to carry out some calculation and then getting back a result. Now the thing is, my result is correct (I did the math on paper to verify), but it's just not in a form I want it to be.
Here's an example. I have a 3D array of the form:
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]]])
I need to convert it to a form where the ith columns of all 2D sub-matrices form a new 2D sub-matrix, as so:
array([[[ 0, 9, 18],
[ 3, 12, 21],
[ 6, 15, 24]],
[[ 1, 10, 19],
[ 4, 13, 22],
[ 7, 16, 25]],
[[2, 11, 20],
[5, 14, 23],
[8, 17, 26]]])
I have tried using various combinations of np.rot90, np.flipud, np.fliplr, all to no avail. Any help on this would be greatly appreciated.
Thanks a lot!
Your desired output is your initial array with the order of the axes reversed. That's how NumPy generalizes transposes to arbitrary-dimensional arrays, so you can use the T attribute for this:
In [3]: x
Out[3]:
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]]])
In [4]: x.T
Out[4]:
array([[[ 0, 9, 18],
[ 3, 12, 21],
[ 6, 15, 24]],
[[ 1, 10, 19],
[ 4, 13, 22],
[ 7, 16, 25]],
[[ 2, 11, 20],
[ 5, 14, 23],
[ 8, 17, 26]]])

Reshaping array into a square array Python

I have an array of numbers whose shape is 26*43264. I would like to reshape this into an array of shape 208*208 but in chunks of 26*26.
[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10,11,12,13,14,15,16,17,18,19]]
becomes something like:
[[0, 1, 2, 3, 4],
[10,11,12,13,14],
[ 5, 6, 7, 8, 9],
[15,16,17,18,19]]
This kind of reshaping question has come up before. But rather than search I'll quickly demonstate a numpy approach
make your sample array:
In [473]: x=np.arange(20).reshape(2,10)
In [474]: x
Out[474]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])
Use reshape to split it into blocks of 5
In [475]: x.reshape(2,2,5)
Out[475]:
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
and use transpose to reorder dimensions, and in effect reorder those rows
In [476]: x.reshape(2,2,5).transpose(1,0,2)
Out[476]:
array([[[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14]],
[[ 5, 6, 7, 8, 9],
[15, 16, 17, 18, 19]]])
and another shape to consolidate the 1st 2 dimensions
In [477]: x.reshape(2,2,5).transpose(1,0,2).reshape(4,5)
Out[477]:
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[ 5, 6, 7, 8, 9],
[15, 16, 17, 18, 19]])
If x is already a numpy array, these transpose and reshape operations are cheap (time wise). If x was really nested lists, then the other solution with list operations will be faster, since making a numpy array has overhead.
A little ugly, but here's a one-liner for the small example that you should be able to modify for the full size one:
In [29]: from itertools import chain
In [30]: np.array(list(chain(*[np.arange(20).reshape(4,5)[i::2] for i in xrange(2)])))
Out[30]:
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[ 5, 6, 7, 8, 9],
[15, 16, 17, 18, 19]])
EDIT: Here's a more generalized version in a function. Uglier code, but the function just takes an array and a number of segments you'd like to end up with.
In [57]: def break_arr(arr, chunks):
....: to_take = arr.shape[1]/chunks
....: return np.array(list(chain(*[arr.take(xrange(x*to_take, x*to_take+to_take), axis=1) for x in xrange(chunks)])))
....:
In [58]: arr = np.arange(40).reshape(4,10)
In [59]: break_arr(arr, 5)
Out[59]:
array([[ 0, 1],
[10, 11],
[20, 21],
[30, 31],
[ 2, 3],
[12, 13],
[22, 23],
[32, 33],
[ 4, 5],
[14, 15],
[24, 25],
[34, 35],
[ 6, 7],
[16, 17],
[26, 27],
[36, 37],
[ 8, 9],
[18, 19],
[28, 29],
[38, 39]])
In [60]: break_arr(arr, 2)
Out[60]:
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[ 5, 6, 7, 8, 9],
[15, 16, 17, 18, 19],
[25, 26, 27, 28, 29],
[35, 36, 37, 38, 39]])

Categories