# Basics of Numpy - Arithmetical operation and arrays handling code samples - 2

Basics of Numpy - Arithmetical operation and arrays handling code samples

Lets explore more on indexing, broadcasting, iterating, manipulations that we perform on ndarray object.

Contents of ndarray object can be accessed and modified by indexing or slicing by

field access, basic slicing and advanced indexing by giving start, stop, and step parameters

a = np.arange(10)

s = slice(2,7,2)

print a[s]

#slicing parameters separated by a colon : (start:stop:step)

b = a[2:7:2]

print b

# slice single item

a = np.arange(10)

b = a

print b

# slice items starting from index

a = np.arange(10)

print a[2:]

# slice items between indexes

print a[2:5]

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

print a

# slice items starting from index

print 'Now we will slice the array from the index a[1:]'

print a[1:]

Slicing can also include ellipsis (…) to make a selection tuple of the same length as the dimension of an array. If ellipsis is used at the row position, it will return an ndarray comprising of items in rows.

# array to begin with

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

print a

# this returns array of items in the second column

print a[...,1]

# Now we will slice all items from the second row

print a[1,...]

# Now we will slice all items from column 1 onwards

print a[...,1:]

There are two types of advanced indexing − Integer and Boolean.

We can make a selection from ndarray that is a non-tuple sequence, ndarray object of integer or Boolean data type, or a tuple with at least one item being a sequence object. Advanced indexing always returns a copy of the data. As against this, the slicing only presents a view.

Integer Indexing

Used to select any arbitrary item in an array based on its Ndimensional index.

Each integer array represents the number of indexes into that dimension.

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

#The selection includes elements at (0,0), (1,1) and (2,0) from the first array.

y = x[[0,1,2], [0,1,0]]

print y

#Output is an ndarray object of corner elements.

x = np.array([[ 0,  1,  2],[ 3,  4,  5],[ 6,  7,  8],[ 9, 10, 11]])

rows = np.array([[0,0],[3,3]])

cols = np.array([[0,2],[0,2]])

y = x[rows,cols]

print y

x = np.array([[ 0,  1,  2],[ 3,  4,  5],[ 6,  7,  8],[ 9, 10, 11]])

# slicing

z = x[1:4,1:3]

# using advanced index for column

y = x[1:4,[1,2]]

print y

#Boolean array indexing

x = np.array([[ 0,  10,  20],[ 30,  40,  50],[ 60,  70,  80],[ 90, 100, 110]])

# Now we will print the items greater than 50

print 'The items greater than 50 are:'

print x[x > 50]

#NaN (Not a Number) elements are omitted by using ~ (complement operator).

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

print a[~np.isnan(a)]

filter out the non-complex elements from an array

a = np.array([1, 2+6j, 5, 3.5+5j])

print a[np.iscomplex(a)]

#broadcasting - Arithmetic operations on arrays are usually done on corresponding elements. If two arrays are of exactly the same shape, then these operations are smoothly performed.

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

b = np.array([10,20,30,40])

c = a * b

print c

#disimilar arrays can be Broadcasted upon by some rules

Broadcasting is possible if the following rules are satisfied −

#Array with smaller ndim than the other is prepended with '1' in its shape.

Size in each dimension of the output shape is maximum of the input sizes in that dimension.

An input can be used in calculation, if its size in a particular dimension matches the output size or its value is exactly 1.

If an input has a dimension size of 1, the first data entry in that dimension is used for all calculations along that dimension.

# A set of arrays is said to be broadcastable if the above rules produce a valid result and one of the following is true −

Arrays have exactly the same shape.

Arrays have the same number of dimensions and the length of each dimension is either a common length or 1.

Array having too few dimensions can have its shape prepended with a dimension of length 1, so that the above stated property is true.

a = np.array([[0.0,0.0,0.0],[10.0,10.0,10.0],[20.0,20.0,20.0],[30.0,30.0,30.0]])

b = np.array([1.0,2.0,3.0])

print a + b

NumPy package contains an iterator object numpy.nditer
a = np.arange(0,60,5)
a = a.reshape(3,4)
print 'Modified array is:'
for x in np.nditer(a):
print x,

#The order of iteration is chosen to match the memory layout of an array, without considering a particular ordering. This can be seen by iterating over the transpose.
a = np.arange(0,60,5)
a = a.reshape(3,4)

#Transpose of the original array is:
b = a.T
for x in np.nditer(b):
print x

#Sorted in C-style order:
c = b.copy(order = 'C')
for x in np.nditer(c):
print x,

#Sorted in F-style order:
c = b.copy(order = 'F')
for x in np.nditer(c):
print x,

#Sorted in C-style order:'
for x in np.nditer(a, order = 'C'):
print x,

#Sorted in F-style order:
for x in np.nditer(a, order = 'F'):
print x,
#The nditer object has another optional parameter called op_flags. Its default value is read-only, but can be set to read-write or write-only mode. This will enable modifying array elements using this iterator.
for x in np.nditer(a, op_flags = ['readwrite']):
x[...] = 2*x
print a
for x in np.nditer(a, flags = ['external_loop'], order = 'F'):
print x,

a = np.arange(0,60,5)
a = a.reshape(3,4)
print a
b = np.array([1, 2, 3, 4], dtype = int)
print b
for x,y in np.nditer([a,b]):
print "%d:%d" % (x,y),

#Array manipulation - Several routines are available in NumPy package for manipulation of elements in ndarray object
They can be broadly classified under Shape, Operation, Dimension,Array,Element

# Shape
#Reshape - Gives a new shape to an array without changing its data
a = np.arange(8)
print a
b = a.reshape(4,2)
print b

#Flat - A 1-D iterator over the array
a = np.arange(8).reshape(2,4)
print a
# returns element corresponding to index in flattened array
print a.flat

#Flatten - Returns a copy of the array collapsed into one dimension
a = np.arange(8).reshape(2,4)
print a
# default is column-major
print a.flatten()
print a.flatten(order = 'F')

#Ravel - Returns a contiguous flattened array
a = np.arange(8).reshape(2,4)
print a
print a.ravel()
print a.ravel(order = 'F')

#Transpose - Permutes the dimensions of an array
a = np.arange(12).reshape(3,4)
print a
print np.transpose(a)

#nDArray.T - Same as self.transpose()
a = np.arange(12).reshape(3,4)
print a.T

#RollAxis- Rolls the specified axis backwards
a = np.arange(8).reshape(2,2,2)
print a
# to roll axis-2 to axis-0 (along width to along depth)
print np.rollaxis(a,2)
# to roll axis 0 to 1 (along width to height)
print np.rollaxis(a,2,1)

#SwapAxes - Interchanges the two axes of an array
a = np.arange(8).reshape(2,2,2)
# now swap numbers between axis 0 (along depth) and axis 2 (along width)
print np.swapaxes(a, 2, 0)