Array indexing#

Numpy offers several ways to index into arrays and accessing/changing specific elements, rows, columns, etc.

Slicing: Similar to Python lists, numpy arrays can be sliced. Since arrays may be multidimensional, you must specify a slice for each dimension of the array:

import numpy as np
a = np.arange(0,11)
a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

Indexing a 1D array#

a[2]           # Get a value at an index
2
a[1:4]         # Get values in a range / slice notation
array([1, 2, 3])
a[:6]
array([0, 1, 2, 3, 4, 5])
a[3:]
array([ 3,  4,  5,  6,  7,  8,  9, 10])
#Slices
slice_a = a[0:5]
slice_a
array([0, 1, 2, 3, 4])
slice_a[:]=100
slice_a
array([100, 100, 100, 100, 100])
a         # Change in original array
array([100, 100, 100, 100, 100,   5,   6,   7,   8,   9,  10])
a_copy = a.copy()   # creat a copy

a_copy
array([100, 100, 100, 100, 100,   5,   6,   7,   8,   9,  10])
a_copy[:]=200
a_copy
array([200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200])
a
array([100, 100, 100, 100, 100,   5,   6,   7,   8,   9,  10])

Be careful when copying arrays!!!#

a = np.array([1,2,3])
a
b = a
#b = a.copy()
b[0] = 100

print(a) 
[100   2   3]

Indexing a 2D array (matrices)#

# mat = [row,col]
# mat = [row][col]
mat=np.array(([5,10,20],[20,25,30],[35,40,10]))
mat
array([[ 5, 10, 20],
       [20, 25, 30],
       [35, 40, 10]])
mat[1] #Indexing row
array([20, 25, 30])
mat[2]
array([35, 40, 10])
# Getting individual element value
mat[1][1]
25
mat[1,2] # use common notaion instaed of 2 brackets
30
#array slicing
mat
array([[ 5, 10, 20],
       [20, 25, 30],
       [35, 40, 10]])
#Shape top row
mat[0]
array([ 5, 10, 20])
#Shape (2,2) from top right corner
mat[:2,1:]
array([[10, 20],
       [25, 30]])
#Shape (2,2) from bottom left corner
mat[1:,:2]
array([[20, 25],
       [35, 40]])
#Shape bottom row
mat[2]
array([35, 40, 10])
#Shape bottom row
mat[2,:]
array([35, 40, 10])
a = np.array([[1,2,3,4,5,6,7],[8,9,10,11,12,13,14]])
print(a)
[[ 1  2  3  4  5  6  7]
 [ 8  9 10 11 12 13 14]]
# Get a specific element [row, column]

a[1, 5]  # to select element '13' we need row 2 and element 6. Hence r=1, c=5 (index start from 0)

# or a[1,-2]
13
# Get a specific row 
a[0, :] # all columns
array([1, 2, 3, 4, 5, 6, 7])
# Get a specific column
a[:, 2] # all rows
array([ 3, 10])
# Getting a little more fancy [startindex:endindex:stepsize]
a[0, 1:-1:2]
array([2, 4, 6])
a[1,5] = 20  # row 2 and element 6
print(a)

a[:,2] = [1,2]
print(a)
[[ 1  2  3  4  5  6  7]
 [ 8  9 10 11 12 20 14]]
[[ 1  2  1  4  5  6  7]
 [ 8  9  2 11 12 20 14]]
# 3D example

b = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
print(b)
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
# Get specific element (work outside in)
b[0,1,1]
4
# replace 
b[:,1,:]
print(b)
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
b[:,1,:] = [[9,9,9],[8,8]]
print(b)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-34-75075a70c90e> in <module>
----> 1 b[:,1,:] = [[9,9,9],[8,8]]
      2 print(b)

ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2,) + inhomogeneous part.

Summary:#

import numpy as np

import numpy as np

# Create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print(a)

# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
#  [6 7]]
b = a[:2, 1:3]
print(b)

# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1])   # Prints "2"
b[0, 0] = 77     # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1])   # Prints "77"
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
[[2 3]
 [6 7]]
2
77

You can also mix integer indexing with slice indexing. However, doing so will yield an array of lower rank than the original array.

Note: this is quite different from the way that MATLAB handles array slicing:

import numpy as np

# Create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print(a)

# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :]    # Rank 1 view of the second row of a
row_r2 = a[1:2, :]  # Rank 2 view of the second row of a
print(row_r1, row_r1.shape)  # Prints "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape)  # Prints "[[5 6 7 8]] (1, 4)"

# We can make the same distinction when accessing columns of an array:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape)  # Prints "[ 2  6 10] (3,)"
print(col_r2, col_r2.shape)  # Prints "[[ 2]
                             #          [ 6]
                             #          [10]] (3, 1)"
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
[5 6 7 8] (4,)
[[5 6 7 8]] (1, 4)
[ 2  6 10] (3,)
[[ 2]
 [ 6]
 [10]] (3, 1)

Integer array indexing#

When you index into numpy arrays using slicing, the resulting array view will always be a subarray of the original array. In contrast, integer array indexing allows you to construct arbitrary arrays using the data from another array. Here is an example:

import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])
print(a)

# An example of integer array indexing.
# The returned array will have shape (3,) and
print(a[[0, 1, 2], [0, 1, 0]])  # Prints "[1 4 5]"

# The above example of integer array indexing is equivalent to this:
print(np.array([a[0, 0], a[1, 1], a[2, 0]]))  # Prints "[1 4 5]"

# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]])  # Prints "[2 2]"

# Equivalent to the previous integer array indexing example
print(np.array([a[0, 1], a[0, 1]]))  # Prints "[2 2]"
[[1 2]
 [3 4]
 [5 6]]
[1 4 5]
[1 4 5]
[2 2]
[2 2]

One useful trick with integer array indexing is selecting or mutating one element from each row of a matrix:

import numpy as np

# Create a new array from which we will select elements
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])

print(a)  # prints "array([[ 1,  2,  3],
          #                [ 4,  5,  6],
          #                [ 7,  8,  9],
          #                [10, 11, 12]])"

# Create an array of indices
b = np.array([0, 2, 0, 1])

# Select one element from each row of a using the indices in b
print(a[np.arange(4), b])  # Prints "[ 1  6  7 11]"

# Mutate one element from each row of a using the indices in b
a[np.arange(4), b] += 10

print(a)  # prints "array([[11,  2,  3],
          #                [ 4,  5, 16],
          #                [17,  8,  9],
          #                [10, 21, 12]])
[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
[ 1  6  7 11]
[[11  2  3]
 [ 4  5 16]
 [17  8  9]
 [10 21 12]]

Quiz time#

# Generate matrix:

###    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

# Acces 
        11 12
        16 17
    
# Acces  
         2
           8
            14
              20

# Acces        
                4  5



               24 25
               29 30

Boolean array indexing#

Boolean array indexing lets you pick out arbitrary elements of an array. Frequently this type of indexing is used to select the elements of an array that satisfy some condition. Here is an example:

a = np.arange(1,11)
a
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
a > 4
array([False, False, False, False,  True,  True,  True,  True,  True,
        True])
bool_a = a>4
bool_a
array([False, False, False, False,  True,  True,  True,  True,  True,
        True])
a[bool_a]
array([ 5,  6,  7,  8,  9, 10])
a[a>2]
array([ 3,  4,  5,  6,  7,  8,  9, 10])
x = 2
a[a>x]
array([ 3,  4,  5,  6,  7,  8,  9, 10])
import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])
print(a)

bool_idx = (a > 2)   # Find the elements of a that are bigger than 2;
                     # this returns a numpy array of Booleans of the same
                     # shape as a, where each slot of bool_idx tells
                     # whether that element of a is > 2.

print(bool_idx)      # Prints "[[False False]
                     #          [ True  True]
                     #          [ True  True]]"

# We use boolean array indexing to construct a rank 1 array
# consisting of the elements of a corresponding to the True values
# of bool_idx
print(a[bool_idx])  # Prints "[3 4 5 6]"

# We can do all of the above in a single concise statement:
print(a[a > 2])     # Prints "[3 4 5 6]"
[[1 2]
 [3 4]
 [5 6]]
[[False False]
 [ True  True]
 [ True  True]]
[3 4 5 6]
[3 4 5 6]

For brevity we have left out a lot of details about numpy array indexing; if you want to know more about Array Indexing you should read this documentation.