Python advanced slicing - python

I am a little confused with Python's advanced slicing. I basically had a dictionary and with help from SO, I made it into an array.
array1 =
([[[36, 16],
[48, 24],
[12, 4],
[12, 4]],
[[48, 24],
[64, 36],
[16, 6],
[16, 6]],
[[12, 4],
[16, 6],
[ 4, 1],
[ 4, 1]],
[[12, 4],
[16, 6],
[ 4, 1],
[ 4, 1]]])
To practice using matrix solver, the array was turned into a square matrix (4 x 4) using:
array_matrix_sized = array[:, :, 0]
I read that this means [number of indices, rows, columns]. I am a little clueless as to why [:,:,0] returns a 4 x 4 matrix. To try to help, I made an array that has a length 100, and I have been trying to turn it into a 10 x 10 matrix in a similar manner with no success. What throws me off is the number of rows is ":" and the number of columns is "0", if I read this concept correctly. For a 4 x 4 matrix, why isn't it array[:, 4, 4]? I am also assuming the : is because I am interested in all the values.
Thank you in advance for any help/advice. I do apologize if this is a simple question, but I really could use the clarification on how this works.
Still not quite understanding.
If I have
array2 = 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, 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, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199])
To get it into a 10 X 10 matrix, I tried using array2[:,:,0] and get the error IndexError: too many indices for array. Isn't this similar to my first example?

I read that this means [number of indices, rows, columns]. [...] What throws me off is the number of rows is ":" and the number of columns is "0", if I read this concept correctly.
No. It means [which parts I want on dimension 1, which parts I want on dimension 2, which parts I want on dimension 3]. The indices are not how many rows/columns you want, they are which ones you want. And, as you said : means "all" in this context.
For a 4 x 4 matrix, why isn't it array[:, 4, 4]?
You don't specify the shape of the result. The shape of the result depends on the shape of the original array. Since your array is 4x4x2, getting one element on the last dimension gives you 4x4. If the array was 8x7x2, then [:, :, 0] would give you an 8x7 result.
So [:, :, 0] means "give me everything on the first two dimensions, but only the first item on the last dimension. This amounts to getting the first element of each "row" (or the first "column" as it appears in the display) which is why you get the result you get:
>>> array1[:, :, 0]
array([[36, 48, 12, 12],
[48, 64, 16, 16],
[12, 16, 4, 4],
[12, 16, 4, 4]])
Likewise, doing [0, :, :] gives you the first "chunk":
>>> array1[0, :, :]
array([[36, 16],
[48, 24],
[12, 4],
[12, 4]])
And doing [:, 0, :] gives you the first row of each chunk:
>>> x[:, 0, :]
array([[36, 16],
[48, 24],
[12, 4],
[12, 4]])

I just wanted to add a clarifying example:
>>> np.arange(4*4*2).reshape(4,4,2)
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]]])
Since we are in three dimensions, we can still maintain a spatial metaphor. Imagine these 4X2 slices were all stacked up against each other, in front of you, in order (like if they were books). That is, we take the first one and prop it up like a book, the second one behind it and so forth. We choose the first chunk from the first dimension, and it merely gives us back the first "book":
>>> a[0,:,:]
array([[0, 1],
[2, 3],
[4, 5],
[6, 7]])
Now look at the difference between that and the first chunk of the second dimension:
>>> a[:,0,:]
array([[ 0, 1],
[ 8, 9],
[16, 17],
[24, 25]])
This is like slicing off the top. Imagine shaving off the top. It just so happens that with the array you posted, these are the same!
Now finally, the first chunk of the third dimension:
>>> a[:,:,0]
array([[ 0, 2, 4, 6],
[ 8, 10, 12, 14],
[16, 18, 20, 22],
[24, 26, 28, 30]])
This is like slicing what you have in front of you in half - imagine a karate-chop.
Here's a (very crude) image (drawn on my laptop...sorry).

The book analogy is good, but I tend to arrange my arrays in a slightly different order. If we consider the following data array...
a = np.arange(2*3*4).reshape(2,3,4)
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]]])
To me, the above reads as 2 pages, one above the other. Each page has 3 rows and there are 4 words in each row.
I wrote a function to take the same information and arrange it side-by-side since this is the way I tend to arrange things I am working on. (details aren't relevant here...). Here is the rearrangement for visual purposes...
a = np.arange(2*3*4).reshape(2,3,4)
Array... shape (2, 3, 4), ndim 3, not masked
0, 1, 2, 3 12, 13, 14, 15
4, 5, 6, 7 16, 17, 18, 19
8, 9, 10, 11 20, 21, 22, 23
sub (0) sub (1)
a[0,:,:]
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
a[:,0,:]
array([[ 0, 1, 2, 3],
[12, 13, 14, 15]])
>>> a[:,:,0]
array([[ 0, 4, 8],
[12, 16, 20]])
So in my case the sequence from a[0,:,:], a[:,0,:] to a[:,:,0] follows the sequence page, row and word.
People can argue from a different perspective, but I think it is important to realize that not all people view things the same way. I often work with images I prefer the above arrangement of (image, row, column) which is equivalent to the (page, row, word) notation.
Do note... if you don't like the way an array looks, or it doesn't work for you... just swap axes.
a.swapaxes(2,0)
array([[[ 0, 12],
[ 4, 16],
[ 8, 20]],
[[ 1, 13],
[ 5, 17],
[ 9, 21]],
[[ 2, 14],
[ 6, 18],
[10, 22]],
[[ 3, 15],
[ 7, 19],
[11, 23]]])
Still not feeling it?... try a different arrangement until it clicks or simplifies your calculations.

code s=np.arange(Total no. of matrices * number of rows * number of columns).reshape(Total no. of matrices * number of rows * number of columns).Example if code is rameez=np.arange(5*4*4).reshape(5,4,4) [[5=Total no of matrices to be generated]].[[4*4 is the 4*4 dimensional matrix]].Here we will get 5 matrices each of which is 4*4 dimensional matrix.Code rameez=np.arange(10*3*2).reshape(10,3,2) will generate 10 matrices as a whole each with the ((3 * 2)) dimensions.

Related

duplicating last column of 3d numpy array

I have the following numpy 3d array, in which I need to duplicate the last column
array([[[ 7, 5, 93],
[19, 4, 69],
[62, 2, 52]],
[[ 6, 1, 65],
[41, 9, 94],
[39, 4, 49]]])
The desired output is:
array([[[ 7, 5, 93, 93],
[19, 4, 69, 69],
[62, 2, 52, 52]],
[[ 6, 1, 65, 65],
[41, 9, 94, 94],
[39, 4, 49, 49]]])
Is there a clever way of doing this?
You could concatenate along the last axis as follows-
numpy.concatenate([a, numpy.expand_dims(a[:, :, -1], axis=2)], axis=2)
There is a built-in numpy function for this purpose:
np.insert(x,-1,x[...,-1],-1)
output:
array([[[ 7, 5, 93, 93],
[19, 4, 69, 69],
[62, 2, 52, 52]],
[[ 6, 1, 65, 65],
[41, 9, 94, 94],
[39, 4, 49, 49]]])

Reshaping rank > 2 numpy arrays in Python

I am working with numpy arrays as rank > 2 tensors in Python and am trying to reshape such a tensor into a matrix, i.e. a rank-2 array. The standard ndarray.reshape() function doesn't really work for this because I need to group the indices of my tensor in a particular way. What I mean is this: say I start with a rank 3 tensor, T_ijk. I am trying to find a function that will output the rank 2 tensor T_(j)(ik), for instance, i.e. for this exampe the desired input/output would be
[Input:] T=np.array([[[1 2]
[3 4]]
[[5 6]
[7 8]]])
[Output:] array([[1, 2, 5, 6],
[3, 4, 7, 8]])
Also, a friend suggested to me that tensorflow might have functions like this, but I've never used it. Does anyone have any insight here?
Try this -
k = 1
m = 2
i = 5
j = 5
l = 2
#dummy T_ijklm
T = np.array(range(100)).reshape(k,m,i,j,l)
T_new = T.reshape(k*m,i*j*l)
print('Original T:',T.shape)
print('New T:',T_new.shape)
#(km)(ijl) = 2*50
Original T: (1, 2, 5, 5, 2)
New T: (2, 50)
New tensor is now a rank 2
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, 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, 64, 65,
66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99]])
In [216]: arr = np.arange(1,9).reshape(2,2,2)
In [217]: arr
Out[217]:
array([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
reshape keeps elements in the original [1,2,3,4,5...] order
In [218]: arr.reshape(2,4)
Out[218]:
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
Figuring out the correct transpose order can be tricky. Sometimes I just try several things. Here I note that you want to preserve the order on the last dimension, so all we have to do is swap the first 2 axes:
In [219]: arr.transpose(1,0,2)
Out[219]:
array([[[1, 2],
[5, 6]],
[[3, 4],
[7, 8]]])
now the reshape does what we want:
In [220]: arr.transpose(1,0,2).reshape(2,4)
Out[220]:
array([[1, 2, 5, 6],
[3, 4, 7, 8]])
This sequence, as best I know, the best "built-in" approach.
You comment:
if I wanted to transform T_ijklmno to T_(ilo)(jmnk) having to figure out which axes to switch and how to reshape will probably get out of hand... that's why I'm looking for an in-built solution
The T_.... notation reminds me that we could use einsum to do the transpose:
In [221]: np.einsum('ijk->jik',arr)
Out[221]:
array([[[1, 2],
[5, 6]],
[[3, 4],
[7, 8]]])
So T_ijklmno to T_(ilo)(jmnk) could become
np.einsum('ijklmno->ilojmnk',T).reshape(I*L*O, J*M*N*K)
T.transpose(0,3,6,1,4,5,2).reshape(...)
(I wrote these by just eyeballing your T expression)
There are so many ways you could transpose and reshape an array with 7 dimensions, that there's little point in coming up with anything more general than the existing methods - transpose, swapaxes, einsum. Simply identifying the dimensions as you do with 'ijk...' is the toughest part of the problem.

Adding a new array to a multidimensional array in Python

I have a numpy array that looks like the following:
np.array([
[23, 12, 4, 103, 87, 0.6],
[32, 18, 3, 120, 70, 0.6],
[43, 12, 8, 109, 89, 0.4],
[20, 13, 7, 111, 77, 0.8]
])
I want to transform this array where the last column becomes its own array, such that it will look like this:
np.array([
[[23, 12, 4, 103, 87], [0.6]],
[[32, 18, 3, 120, 70], [0.6]],
[[43, 12, 8, 109, 89], [0.4]],
[[20, 13, 7, 111, 77], [0.8]]
])
What would be the best way to go about this? I am relatively new to Python and have tried out some loops but to no avail. Thanks!
numpy requires consistent dimensions in its array; that would give two different sizes. You can either use two separate variables (i.e. parallel arrays):
X = data[:, :-1]
y = data[:, -1]
X = np.array([
[23, 12, 4, 103, 87],
[32, 18, 3, 120, 70],
[43, 12, 8, 109, 89],
[20, 13, 7, 111, 77],
])
y = np.array([
0.6, 0.6, 0.4, 0.8
])
Or you can store a list of pairs:
my_list = [(row[:-1], [row[-1]]) for row in data]
my_list = [
([23, 12, 4, 103, 87], [0.6]),
([32, 18, 3, 120, 70], [0.6]),
([43, 12, 8, 109, 89], [0.4]),
([20, 13, 7, 111, 77], [0.8])
]
The best strategy depends on your use case.

numpy select columns and rows with lists [duplicate]

I have looked into documentations and also other questions here, but it seems I
have not got the hang of subsetting in numpy arrays yet.
I have a numpy array,
and for the sake of argument, let it be defined as follows:
import numpy as np
a = np.arange(100)
a.shape = (10,10)
# 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, 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, 64, 65, 66, 67, 68, 69],
# [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
# [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
# [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
now I want to choose rows and columns of a specified by vectors n1 and n2. As an example:
n1 = range(5)
n2 = range(5)
But when I use:
b = a[n1,n2]
# array([ 0, 11, 22, 33, 44])
Then only the first fifth diagonal elements are chosen, not the whole 5x5 block. The solution I have found is to do it like this:
b = a[n1,:]
b = b[:,n2]
# array([[ 0, 1, 2, 3, 4],
# [10, 11, 12, 13, 14],
# [20, 21, 22, 23, 24],
# [30, 31, 32, 33, 34],
# [40, 41, 42, 43, 44]])
But I am sure there should be a way to do this simple task in just one command.
You've gotten a handful of nice examples of how to do what you want. However, it's also useful to understand the what's happening and why things work the way they do. There are a few simple rules that will help you in the future.
There's a big difference between "fancy" indexing (i.e. using a list/sequence) and "normal" indexing (using a slice). The underlying reason has to do with whether or not the array can be "regularly strided", and therefore whether or not a copy needs to be made. Arbitrary sequences therefore have to be treated differently, if we want to be able to create "views" without making copies.
In your case:
import numpy as np
a = np.arange(100).reshape(10,10)
n1, n2 = np.arange(5), np.arange(5)
# Not what you want
b = a[n1, n2] # array([ 0, 11, 22, 33, 44])
# What you want, but only for simple sequences
# Note that no copy of *a* is made!! This is a view.
b = a[:5, :5]
# What you want, but probably confusing at first. (Also, makes a copy.)
# np.meshgrid and np.ix_ are basically equivalent to this.
b = a[n1[:,None], n2[None,:]]
Fancy indexing with 1D sequences is basically equivalent to zipping them together and indexing with the result.
print "Fancy Indexing:"
print a[n1, n2]
print "Manual indexing:"
for i, j in zip(n1, n2):
print a[i, j]
However, if the sequences you're indexing with match the dimensionality of the array you're indexing (2D, in this case), The indexing is treated differently. Instead of "zipping the two together", numpy uses the indices like a mask.
In other words, a[[[1, 2, 3]], [[1],[2],[3]]] is treated completely differently than a[[1, 2, 3], [1, 2, 3]], because the sequences/arrays that you're passing in are two-dimensional.
In [4]: a[[[1, 2, 3]], [[1],[2],[3]]]
Out[4]:
array([[11, 21, 31],
[12, 22, 32],
[13, 23, 33]])
In [5]: a[[1, 2, 3], [1, 2, 3]]
Out[5]: array([11, 22, 33])
To be a bit more precise,
a[[[1, 2, 3]], [[1],[2],[3]]]
is treated exactly like:
i = [[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
j = [[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]
a[i, j]
In other words, whether the input is a row/column vector is a shorthand for how the indices should repeat in the indexing.
np.meshgrid and np.ix_ are just convienent ways to turn your 1D sequences into their 2D versions for indexing:
In [6]: np.ix_([1, 2, 3], [1, 2, 3])
Out[6]:
(array([[1],
[2],
[3]]), array([[1, 2, 3]]))
Similarly (the sparse argument would make it identical to ix_ above):
In [7]: np.meshgrid([1, 2, 3], [1, 2, 3], indexing='ij')
Out[7]:
[array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]]),
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])]
Another quick way to build the desired index is to use the np.ix_ function:
>>> a[np.ix_([n1, n2])]
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44]])
This provides a convenient way to construct an open mesh from sequences of indices.
You could use np.meshgrid to give the n1, n2 arrays the proper shape to perform the desired indexing:
In [104]: a[np.meshgrid(n1,n2, sparse=True, indexing='ij')]
Out[104]:
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44]])
Or, without meshgrid:
In [117]: a[np.array(n1)[:,np.newaxis], np.array(n2)[np.newaxis,:]]
Out[117]:
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44]])
There is a similar example with an explanation of how this integer array indexing works in the docs.
See also the Cookbook recipe Picking out rows and columns.
A nice Trick I've managed to pull (for lazy people only)
Is filter + Transpose + filter.
a = np.arange(100).reshape(10,10)
subsetA = [1,3,5,7]
a[subsetA].T[subsetA]
array([[11, 31, 51, 71],
[13, 33, 53, 73],
[15, 35, 55, 75],
[17, 37, 57, 77]])
It seems that a use case for your particular question would deal with image manipulation. To the extent that you are using your example to edit numpy arrays arising from images, you can use the Python Imaging Library (PIL).
# Import Pillow:
from PIL import Image
# Load the original image:
img = Image.open("flowers.jpg")
# Crop the image
img2 = img.crop((0, 0, 5, 5))
The img2 object is a numpy array of the resulting cropped image.
You can read more about image manipulation here with the Pillow package (a user friendly fork on the PIL package):

Subsetting a 2D numpy array

I have looked into documentations and also other questions here, but it seems I
have not got the hang of subsetting in numpy arrays yet.
I have a numpy array,
and for the sake of argument, let it be defined as follows:
import numpy as np
a = np.arange(100)
a.shape = (10,10)
# 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, 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, 64, 65, 66, 67, 68, 69],
# [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
# [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
# [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
now I want to choose rows and columns of a specified by vectors n1 and n2. As an example:
n1 = range(5)
n2 = range(5)
But when I use:
b = a[n1,n2]
# array([ 0, 11, 22, 33, 44])
Then only the first fifth diagonal elements are chosen, not the whole 5x5 block. The solution I have found is to do it like this:
b = a[n1,:]
b = b[:,n2]
# array([[ 0, 1, 2, 3, 4],
# [10, 11, 12, 13, 14],
# [20, 21, 22, 23, 24],
# [30, 31, 32, 33, 34],
# [40, 41, 42, 43, 44]])
But I am sure there should be a way to do this simple task in just one command.
You've gotten a handful of nice examples of how to do what you want. However, it's also useful to understand the what's happening and why things work the way they do. There are a few simple rules that will help you in the future.
There's a big difference between "fancy" indexing (i.e. using a list/sequence) and "normal" indexing (using a slice). The underlying reason has to do with whether or not the array can be "regularly strided", and therefore whether or not a copy needs to be made. Arbitrary sequences therefore have to be treated differently, if we want to be able to create "views" without making copies.
In your case:
import numpy as np
a = np.arange(100).reshape(10,10)
n1, n2 = np.arange(5), np.arange(5)
# Not what you want
b = a[n1, n2] # array([ 0, 11, 22, 33, 44])
# What you want, but only for simple sequences
# Note that no copy of *a* is made!! This is a view.
b = a[:5, :5]
# What you want, but probably confusing at first. (Also, makes a copy.)
# np.meshgrid and np.ix_ are basically equivalent to this.
b = a[n1[:,None], n2[None,:]]
Fancy indexing with 1D sequences is basically equivalent to zipping them together and indexing with the result.
print "Fancy Indexing:"
print a[n1, n2]
print "Manual indexing:"
for i, j in zip(n1, n2):
print a[i, j]
However, if the sequences you're indexing with match the dimensionality of the array you're indexing (2D, in this case), The indexing is treated differently. Instead of "zipping the two together", numpy uses the indices like a mask.
In other words, a[[[1, 2, 3]], [[1],[2],[3]]] is treated completely differently than a[[1, 2, 3], [1, 2, 3]], because the sequences/arrays that you're passing in are two-dimensional.
In [4]: a[[[1, 2, 3]], [[1],[2],[3]]]
Out[4]:
array([[11, 21, 31],
[12, 22, 32],
[13, 23, 33]])
In [5]: a[[1, 2, 3], [1, 2, 3]]
Out[5]: array([11, 22, 33])
To be a bit more precise,
a[[[1, 2, 3]], [[1],[2],[3]]]
is treated exactly like:
i = [[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
j = [[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]
a[i, j]
In other words, whether the input is a row/column vector is a shorthand for how the indices should repeat in the indexing.
np.meshgrid and np.ix_ are just convienent ways to turn your 1D sequences into their 2D versions for indexing:
In [6]: np.ix_([1, 2, 3], [1, 2, 3])
Out[6]:
(array([[1],
[2],
[3]]), array([[1, 2, 3]]))
Similarly (the sparse argument would make it identical to ix_ above):
In [7]: np.meshgrid([1, 2, 3], [1, 2, 3], indexing='ij')
Out[7]:
[array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]]),
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])]
Another quick way to build the desired index is to use the np.ix_ function:
>>> a[np.ix_([n1, n2])]
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44]])
This provides a convenient way to construct an open mesh from sequences of indices.
You could use np.meshgrid to give the n1, n2 arrays the proper shape to perform the desired indexing:
In [104]: a[np.meshgrid(n1,n2, sparse=True, indexing='ij')]
Out[104]:
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44]])
Or, without meshgrid:
In [117]: a[np.array(n1)[:,np.newaxis], np.array(n2)[np.newaxis,:]]
Out[117]:
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44]])
There is a similar example with an explanation of how this integer array indexing works in the docs.
See also the Cookbook recipe Picking out rows and columns.
A nice Trick I've managed to pull (for lazy people only)
Is filter + Transpose + filter.
a = np.arange(100).reshape(10,10)
subsetA = [1,3,5,7]
a[subsetA].T[subsetA]
array([[11, 31, 51, 71],
[13, 33, 53, 73],
[15, 35, 55, 75],
[17, 37, 57, 77]])
It seems that a use case for your particular question would deal with image manipulation. To the extent that you are using your example to edit numpy arrays arising from images, you can use the Python Imaging Library (PIL).
# Import Pillow:
from PIL import Image
# Load the original image:
img = Image.open("flowers.jpg")
# Crop the image
img2 = img.crop((0, 0, 5, 5))
The img2 object is a numpy array of the resulting cropped image.
You can read more about image manipulation here with the Pillow package (a user friendly fork on the PIL package):

Categories