Prev: Array construction (cont'd)       |       Next: Array slicing

# Array indexing¶

• Indexing in ndarrays works mostly as in lists. However, some powerful indexing possibilities are available that make programming of complex tasks a lot easier. We explore some of these further below.

#### 1D array¶

• As in lists
In [1]:
import numpy as np
ar = np.linspace(0,10,8, False)
print(ar, '\n')
print(ar[0], ar[2], ar[len(ar)-1], ar[-1], ar[-len(ar)], sep=', ')

[ 0.    1.25  2.5   3.75  5.    6.25  7.5   8.75]

0.0, 2.5, 8.75, 8.75, 0.0


#### 2D array¶

• As in lists but syntax is more flexible
In [2]:
import numpy as np
ar = np.arange(20).reshape(2,10)
print(ar)
print(ar[0][len(ar[0])-1])
print(ar[0,len(ar)])                # Remember that len(ar) equals '2' (number of list members)

# three syntactic forms are acceptable
print(ar[1,2], ar[0][5], ar[(1,0)])

[[ 0  1  2  3  4  5  6  7  8  9]
[10 11 12 13 14 15 16 17 18 19]]
9
2
12 5 10

• Note, however, that in occasions things might work counterintuitive and deeper investigation is needed to understand the computational representation of arrays.
• See the following example:
In [3]:
import numpy as np
ar = np.array([[1,2,3,4],[5,6,7,8,9,10]])     # ar is now a 'ragged' array due to uneven lists

print(ar.ndim)            # strangely its dimension is 1. Why?
print(ar.dtype)           # why is dtype 'object' and not integer?

1
object

• Answer: because length of lists is different in array(0), numpy can not construct a homogeneous array object with integers. Instead the array 'ar' is constructed as 1D array with two members of dtype 'object'. Pointers are used in this case to point to the integer member items.
• And what if we want to have 'ar' as a 1D array with 10 integer member items? We can use the concatenate() function to flatten the array
In [4]:
ar = np.concatenate(ar)
print(ar)
print(ar.ndim, ar.dtype)

[ 1  2  3  4  5  6  7  8  9 10]
1 int32


#### 3D array¶

In [5]:
import numpy as np
ar = np.arange(1,17).reshape(2,2,4)
print(ar,'\n')
print(ar[0,1,2], ar[1,1,1], ar[0][1][3], ar[(1,1,3)])
print()
print(ar[0,1,len(ar)], ar[len(ar)-1,len(ar[1])-1,len(ar[0][1])-1],
ar[0][1][3], ar[(1,1,1)])

[[[ 1  2  3  4]
[ 5  6  7  8]]

[[ 9 10 11 12]
[13 14 15 16]]]

7 14 8 16

7 16 8 14


### Printing 2D array example¶

• Construct a two-dimensional array with 10 pseudo-random integers in [1,100] (5 in each of two rows). Then:
• (a) Print the rows one below the other (no indexing)
• (b) Similar to (a) but using single indexing for the rows
• (c) Print the array members (one by the other in a row; no indexing)
• (d) Similar to (c) but using double indices for the single array members
• (e) Using the .format() method.
In [6]:
import numpy as np

ar = np.array([[np.random.randint(1,101) for i in range(5)],
[np.random.randint(1,101) for i in range(5)]])

#(a)
for i in ar:
print(i)

[32  5 25 81 87]
[31 37 49 77  6]

In [7]:
#(b)
for i in [0,1]:
print(ar[i])

[32  5 25 81 87]
[31 37 49 77  6]

In [8]:
#(c)
for i in ar:
for k in i:
print(k, end=' ')

32 5 25 81 87 31 37 49 77 6
In [9]:
#(d)
for i in [0,1]:
for m in [0,1,2,3,4]:
print(ar[i][m], end=' ')
print()

32 5 25 81 87
31 37 49 77 6

In [10]:
#(e)
print('{:} {:}'.format(*(ar)))

[32  5 25 81 87] [31 37 49 77  6]


## Assignment¶

• Assignment in arrays works much as expected (like in lists) but with few notable differences:
• Arrays are homogeneous constructs (lists are heterogeneous) so they normally expect new assigned values to be of the same type object
In [11]:
import numpy as np
ar = np.arange(20).reshape(2,10)

ar[0][0] = 100
ar
#ar[0][0] = 'X'    # but this is NOT valid in an array of integers

Out[11]:
array([[100,   1,   2,   3,   4,   5,   6,   7,   8,   9],
[ 10,  11,  12,  13,  14,  15,  16,  17,  18,  19]])
In [12]:
ar[0][0] = '200'   # this is accepted as digit-based string is trasformed to integer
ar

Out[12]:
array([[200,   1,   2,   3,   4,   5,   6,   7,   8,   9],
[ 10,  11,  12,  13,  14,  15,  16,  17,  18,  19]])
• Array broadcasting: assignment works if numpy can broadcast the array and array-like new values in the assignment
• 'Broadcasting' is a term referring to compatibility of array shapes. For more explanations on array broadcasting see the section on array operations
In [13]:
import numpy as np
ar = np.arange(20).reshape(4,5)
print(ar,'\n')

ar[0] = 100   # a scalar is 'broadcast' across the 1D ar[0] array
print(ar)

[[ 0  1  2  3  4]
[ 5  6  7  8  9]
[10 11 12 13 14]
[15 16 17 18 19]]

[[100 100 100 100 100]
[  5   6   7   8   9]
[ 10  11  12  13  14]
[ 15  16  17  18  19]]

In [14]:
import numpy as np
ar = np.arange(20).reshape(4,5)
print(ar,'\n')

# this will not work: numpy does not broadcast a 1D array with 3 members on the 5 member ar[0]
#ar[0] = [100,200,300]

# but this will work because shapes are compatible
ar[0] = [100,200,300,400,500]
print(ar)

[[ 0  1  2  3  4]
[ 5  6  7  8  9]
[10 11 12 13 14]
[15 16 17 18 19]]

[[100 200 300 400 500]
[  5   6   7   8   9]
[ 10  11  12  13  14]
[ 15  16  17  18  19]]


## Fancy indexing¶

• 'Fancy indexing' is a general term referring to various non-standard ways of array indexing. By 'standard' we mean the routinely used integer-based indexing.
• Two interesting 'fancy indexing' methods are shown below.

• Suppose we want to extract from array 'ar' only the members with even index value. One way to do it with fancy indexing is the following:
In [15]:
import numpy as np
ar = np.random.random_integers(0, 100, 10)    # See numpy.random documentation for this
print(ar)

mask = (ar%2==0)          # mask is array constructed by applying a boolean expression on 'ar'

new_ar = ar[mask]         # new_ar is constructed by using mask as array index
print('new_ar =',new_ar)  # the new_ar contains the 'True' members of original ar

[73  5 82 92 67 33 92 70 51 78]
[False False  True  True False False  True  True False  True]
new_ar = [82 92 92 70 78]


#### List of integers¶

• Suppose we want to construct a new array from the original array 'ar' by repeating twice the values of 'ar' with even index value. We can do that applying the list-of-integers fancy indexing method:
In [16]:
import numpy as np
ar = np.random.random_integers(0, 100, 10)
print(ar)

alist = [i if i%2==1 else i-1 for i in range(1,11)]
print(alist)                # a list of integers is constructed with the required indices

new_ar = ar[alist]          # new_ar is constructed by using alist as array index
print('new_ar =',new_ar)

[58 46 99 75 10 92 74 25 81  5]
[1, 1, 3, 3, 5, 5, 7, 7, 9, 9]
new_ar = [46 46 75 75 92 92 25 25  5  5]


. Free learning material
. See full copyright and disclaimer notice