Python NumPy

NumPy — Numerical Python, for working with arrays. Python’s built-in lists serve the same purpose but are slow. NumPy arrays are up to 50× faster — they’re stored at one continuous place in memory (locality of reference), so processes can access and manipulate them efficiently.

Part 1 — Creating arrays & data types

Creating an array

import numpy as np
 
arr = np.array([1, 2, 3, 4, 5])
 
arr = np.arrange(2, 10, 2)
>> [2, 4, 6, 8]
 
arr = np.arrange(10)
>> [1, 2, 3, 4, 5, 6, 7, 8, 9]
# array in NumPy is called ndarray
 
arr = np.linspace(-2, 5, 50)   # 50 data points including -2 and 5
# Generates a numpy array of numbers EVENLY SPACED over a specified interval

Dimensions

# 0-D Arrays / Scalars are elements in an array
arr = np.array(42)
 
# 1-D Arrays: made up of 0-D array elements. Uni-dimensional
arr = np.array([1, 2, 3, 4, 5])
 
# 2-D Arrays: made up of 1-D array elements. Matrix / 2nd-order tensor
arr = np.array([[1, 2, 3], [4, 5, 6]])
 
# 3-D Arrays: made up of 2-D array elements. 3rd-order tensor
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
 
arr.ndm                            # Check number of dimensions
np.array([1, 2, 3], ndim=5)        # Define number of dimensions
# in this example, [1, 2, 3] is the innermost dimension with 3 elements.

Array indexing

# It always goes from macro to micro.
 
# Access 1-D Arrays
arr = np.array([1, 2, 3, 4])
print(arr[0])
>> 1
 
print(arr[1] + arr[2])
>> 5
 
# Access 2-D Arrays: Table with rows and columns
# [x, y]: x array/row, y element/column
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr[0, 1])
>> 2
 
# Access 3-D Arrays
# [x, y, z]: x array, y array, z element
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(arr[0, 1, 2])
>> 6
 
# Negative indexing
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr[1, -1])
>> 6

Array slicing

# [start:end:step]
# start is inclusive, end is exclusive
# you can use x:y to select elements or arrays
 
# 1D array
arr = np.array([1, 2, 3, 4, 5, 6, 7])
print(arr[1:5])
>> [2, 3, 4, 5]
 
print(arr[1:5:2])
>> [2, 4]
 
print(arr[2:])
>> [3, 4, 5, 6, 7]
# vice versa for :4 but not included
 
print(arr[-3:-1])
>> [5, 6]
 
# 2D Arrays
print(arr[1, 1:4])      # Second array, elements index 1-4
print(arr[0:2, 2])      # Take the array index 0 and 1. Element index 2 in both.
print(arr[0:2, 0:2])    # Take the array index 0 and 1. Element index 0 and 1 in both.

Data types

# Data types
i  # integer
b  # boolean
u  # unsigned integer
f  # float
c  # complex float
m  # timedelta
M  # datetime
O  # object
S  # string
U  # unicode string
V  # fixed chunk of memory for other type
 
# Checking data type
arr.dtype
 
# Create array with data type
arr = np.array([1, 2, 3], dtype='S')    # string
arr = np.array([1, 2, 3], dtype='i4')   # 4 bytes integer
 
# Convert data type on existing array
arr = np.array([1, 2, 3])
new_arr = arr.astype('i')

Part 2 — Copy vs View, Shape, Reshape, Iterate

Copy vs View

Copy is a new array. View is a view of the original array.

arr = np.array([1, 2, 3])
 
# COPY: Owns its data
# Whatever changes are made to original/copy does not affect copy/original
copy_arr = arr.copy()
 
# VIEW: Does not own its data
# Whatever changes are made to original/view affects view/original
view_arr = arr.view()
 
# Check if Array owns its data
# Every NP array has the attribute base that returns None if array owns data.
print(copy_arr.base)
print(view_arr.base)
 
>> None
>> [1, 2, 3]

Array shapes

# Shape of 2D array
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape)
 
>> (2, 3)
# 2 dimensions, each with 3 elements
 
# For higher dimensions
arr = np.array([1, 2, 3], ndmin=5)
print(arr)
print(arr.shape)
 
>> [[[[[1, 2, 3]]]]]
>> (1, 1, 1, 1, 3)

Array reshaping

arr.reshape(x, y, ...)
# number of arrays, number of elements (or arrays) in each array
# make sure you count the grouping properly
# reshaped array is a view
 
# EG: Reshaping a 1-D array into 2-D array
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
new_arr = arr.reshape(2, 5)
print(new_arr)
 
>> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
 
# Unknown dimensions (Convert 1-D into 3-D)
# You skipping a dimension?
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
new_arr = arr.reshape(2, 2, -1)
print(new_arr)
 
>> [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
 
# Flattening arrays
arr = np.array([[1, 2, 3], [4, 5, 6]])
new_arr = arr.reshape(-1)
print(new_arr)
 
>> [1, 2, 3, 4, 5, 6]

Array iterating

# 1-D iterating
arr = np.array([1, 2, 3])
 
for x in arr:
    print(x)
 
# 2-D iterating
arr = np.array([[1, 2, 3], [4, 5, 6]])
 
for x in arr:
    print(x)
 
>> [1, 2, 3]
>> [4, 5, 6]
 
# 2-D iterating (to get the elements)
for x in arr:
    for y in x:
        print(y)

nditer()

arr = np.array(the craziest dimensions)
 
# Gets the basic elements
for x in np.nditer(arr):
    print(x)
 
# Gets the basic elements, change datatype of elements while iterating
for x in np.nditer(arr, flags=['buffered'], op_dtypes=['S']):
    print(x)
 
# Gets the basic elements, skipping elements
for x in np.nditer(arr[x:y...]):
    print(x)

ndenumerate()

# 1-D Array
arr = np.array([1, 2, 3])
 
for idx, x in np.ndenumerate(arr):
    print(idx, x)
 
>> (0,) 1
>> (1,) 2
>> (2,) 3
 
# 2-D Array
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
 
for idx, x in np.ndenumerate(arr):
    print(idx, x)
 
>> (0, 0) 1
>> (0, 1) 2
>> (0, 2) 3
>> (0, 3) 4
>> (1, 0) 5
>> (1, 1) 6
>> (1, 2) 7
>> (1, 3) 8

Part 3 — Joining

Array joining using axes

arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr3 = np.concatenate((arr1, arr2))
 
>> [1, 2, 3, 4, 5, 6]

Part 4 — NumPy operations

print(a.shape)        # Return the shape or number of elements in a 1D array
print(a - 5)          # Subtract each element by 5
print(a**2)           # Square each element
print(a*2)            # Each element * 2
print(a/16)           # Divide each element by 16
print(np.sqrt(a))     # Perform the square root of each element
print(np.sum(a))      # Sum all elements
print(np.min(a))      # Return the minimum
print(np.max(a))      # Return the maximum
print(np.sort(a))     # Sort from minimum to maximum
print(np.mean(a))     # Return the mean
print(np.median(a))   # Return the median
print(np.std(a))      # Return the standard deviation

See next