Related
I would like to extract maximum x values in different positions and save their position.
[[ 5, 57, 66, 59, 26],
[23, 66, 97, 96, 33],
[31, 63, 69, 55, 20],
[ 2, 77, 37, 85, 40],
[87, 94, 43, 92, 44],
]
Thanks
Using max with a range over an array is one way to get the index of the maximum element:
>>> [max(range(len(row)), key=row.__getitem__) for row in m]
[2, 2, 2, 3, 1]
Another option would be to use index after getting the max element itself (this is slightly less efficient because now you're scanning each row twice, but the difference is a constant factor):
>>> [row.index(max(row)) for row in m]
[2, 2, 2, 3, 1]
It's not totally clear if you want n randomly chosen or n largest items. I include solutions for both interpretations because they are very similar
Assuming you want 8 randomly chosen items from a 2D array and their positions
import numpy as np
x = np.array(
[[ 5, 57, 66, 59, 26],
[23, 66, 97, 96, 33],
[31, 63, 69, 55, 20],
[ 2, 77, 37, 85, 40],
[87, 94, 43, 92, 44]])
Create a random boolean matrix to choose the items
how_many = 8
choices = [True] * how_many + [False] * (len(x.ravel()) - how_many)
choices = np.random.permutation(choices).reshape(x.shape)
x[choices]
Out:
array([66, 59, 23, 33, 63, 69, 20, 40])
To get their positions
positions_2D = np.vstack(np.unravel_index(np.flatnonzero(choices), x.shape)).T
positions_2D
Out:
array([[0, 2],
[0, 3],
[1, 0],
[1, 4],
[2, 1],
[2, 2],
[2, 4],
[3, 4]])
To get the chosen items by 2D coordinates
x[positions_2D[:,0], positions_2D[:,1]]
Out:
array([66, 59, 23, 33, 63, 69, 20, 40])
If you want the 8 largest items it is the same approach without the boolean array to choose the items
top_8_positions_in_2D = np.vstack(np.unravel_index(x.argsort(None), x.shape)).T[:-9:-1]
x[top_8_positions_in_2D[:,0], top_8_positions_in_2D[:,1]]
Out:
array([97, 96, 94, 92, 87, 85, 77, 69])
To get their 2D coordinates
top_8_positions_in_2D
Out:
array([[1, 2],
[1, 3],
[4, 1],
[4, 3],
[4, 0],
[3, 3],
[3, 1]])
This question already has answers here:
Index n dimensional array with (n-1) d array
(3 answers)
Closed 2 years ago.
I have two arrays, and are as follows:
import numpy as np
np.random.seed(42)
a = (np.random.uniform(size=[2, 5, 3]) * 100).astype(int)
b = (np.random.uniform(size=[2, 5, 3]) * 100).astype(int)
Ouput of array a:
array([[[37, 95, 73],
[59, 15, 15],
[ 5, 86, 60],
[70, 2, 96],
[83, 21, 18]],
[[18, 30, 52],
[43, 29, 61],
[13, 29, 36],
[45, 78, 19],
[51, 59, 4]]])
The output of array b is as follows:
array([[[60, 17, 6],
[94, 96, 80],
[30, 9, 68],
[44, 12, 49],
[ 3, 90, 25]],
[[66, 31, 52],
[54, 18, 96],
[77, 93, 89],
[59, 92, 8],
[19, 4, 32]]])
Now I am able to get the argmax of array a using the following code:
idx = np.argmax(a, axis=0)
print(idx)
Output:
array([[0, 0, 0],
[0, 1, 1],
[1, 0, 0],
[0, 1, 0],
[0, 1, 0]], dtype=int64)
Is it possible to slice array b using the argmax output of array a, so that I get the following output:
array([[60, 17, 6],
[94, 18, 96],
[77, 9, 68],
[44, 92, 49],
[ 3, 4, 25]])
I tried different ways, but not successful. Kindly help.
Using numpy advanced indexing:
import numpy as np
np.random.seed(42)
a = (np.random.uniform(size=[2, 5, 3]) * 100).astype(int)
b = (np.random.uniform(size=[2, 5, 3]) * 100).astype(int)
idx = np.argmax(a, axis=0)
_, m, n = a.shape
b[idx, np.arange(m)[:,None], np.arange(n)]
array([[60, 17, 6],
[94, 18, 96],
[77, 9, 68],
[44, 92, 49],
[ 3, 4, 25]])
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.
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):
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):