2.2. Numpy#

last update: Feb 07, 2024

Numpy is a Python library for scientific computing. It provides high-performance multidimensional arrays and matrices, and efficient tools for working with these objects.

import numpy as np

2.2.1. Create numpy arrays#

A basic way to create an array is to use the function np.array(). It takes a list as an argument and returns a numpy array.

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

In numpy, there are many methods to create arrays. For example, np.arange() creates an array of integers, np.zeros() creates an array of zeros, and np.ones() creates an array of ones.

np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.arange(1, 10, 2)
array([1, 3, 5, 7, 9])
np.zeros(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
np.zeros((3, 5))
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])
np.ones(10)
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
np.ones((3, 5))
array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]])

np.random.?? makes random arrays.

np.random.rand() makes an array of random numbers from the uniform distribution between 0 and 1.

np.random.randn() makes an array of random numbers from the standard normal distribution.

np.random.randint(low, high, size) makes an array of random integers between low and high.

np.random.choice(a, size, replace=True, p=None) makes an array of random numbers from the list a.

np.random.seed(0)

print("np.random.rand(5) = ", np.random.rand(5), sep="\n", end="\n\n")

print("np.random.randn(5) = ", np.random.randn(5), sep="\n", end="\n\n")

print("np.random.rand(3, 5) = ", np.random.rand(3, 5), sep="\n", end="\n\n")

print("np.random.randint(low=1, high=10, size=5) = ", np.random.randint(low=1, high=10, size=5), end="\n\n")

print("np.random.randint(10) = ", np.random.randint(10), end="\n\n")

print("np.random.randint(1, 10, (3, 5)) = ", np.random.randint(1, 10, (3, 5)), sep="\n")

print("np.random.choice(['a', 'b', 'c'], 10) = ", np.random.choice(["a", "b", "c"], 10), sep="\n", end="\n\n")
np.random.rand(5) = 
[0.5488135  0.71518937 0.60276338 0.54488318 0.4236548 ]

np.random.randn(5) = 
[-0.84272405  1.96992445  1.26611853 -0.50587654  2.54520078]

np.random.rand(3, 5) = 
[[0.92559664 0.07103606 0.0871293  0.0202184  0.83261985]
 [0.77815675 0.87001215 0.97861834 0.79915856 0.46147936]
 [0.78052918 0.11827443 0.63992102 0.14335329 0.94466892]]

np.random.randint(low=1, high=10, size=5) =  [5 8 4 3 8]

np.random.randint(10) =  2

np.random.randint(1, 10, (3, 5)) = 
[[1 1 5 6 6]
 [7 9 5 2 5]
 [9 2 2 8 4]]
np.random.choice(['a', 'b', 'c'], 10) = 
['c' 'c' 'c' 'a' 'c' 'b' 'a' 'b' 'c' 'a']

np.linspace(start, stop, num, endpoint=True) creates an array of evenly spaced numbers over a specified interval. This can be useful for plotting functions.

np.linspace(0, 1, 6)
array([0. , 0.2, 0.4, 0.6, 0.8, 1. ])

np.eye() creates an matrix with ones on the diagonal and zeros elsewhere. You can also make non-square identity matrices by specifying the number of rows and columns.

np.eye(3, 5)
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.]])
np.eye(5)  # This is the same as np.identity(5)
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])
np.identity(5)
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])

np.emtpy() creates an array of uninitialized (arbitrary) data of the given shape and dtype. It is used when you want to create an array and then fill it with data later. It is faster than creating an array of zeros or ones using np.zeros() or np.ones().

np.empty(10)
array([1.e-323, 1.e-323, 1.e-323, 0.e+000, 1.e-323, 5.e-324, 0.e+000,
       5.e-324, 1.e-323, 0.e+000])

np.zeros_like((), np.ones_like(), np.empty_like() create arrays of zeros, ones, or uninitialized data with the same shape and dtype as the given array.

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

np.zeros_like(a)
array([[0, 0, 0],
       [0, 0, 0]])
np.full((3, 5), 3)
array([[3, 3, 3, 3, 3],
       [3, 3, 3, 3, 3],
       [3, 3, 3, 3, 3]])
np.fromfunction(lambda i, j: i + j, (3, 5))
array([[0., 1., 2., 3., 4.],
       [1., 2., 3., 4., 5.],
       [2., 3., 4., 5., 6.]])

2.2.2. Manipulating arrays#

# Append 4 to a
a = np.array([1, 2, 3])
b = np.append(a, 4)
print(b)
[1 2 3 4]
# Delete a[1]
a = np.array([1, 2, 3])
b = np.delete(a, 1)
print(b)
[1 3]
# Sort a
a = np.array([3, 2, 1])
b = np.sort(a)
print(b)
[1 2 3]
# Concatenate two arrays
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.concatenate((a, b))
print(c)
[1 2 3 4 5 6]
# Reshape an array
a = np.array([1, 2, 3, 4, 5, 6])
print("a.shape ", a.shape)
b = a.reshape(2, 3)
print("b = ", b)
print("b.shape ", b.shape)
a.shape  (6,)
b =  [[1 2 3]
 [4 5 6]]
b.shape  (2, 3)
# Conditional selection
a = np.array([1, 2, 3, 4, 5, 6])
print(a > 3)
print(a[a > 3])
[False False False  True  True  True]
[4 5 6]
# Slice an array
a = np.array([1, 2, 3, 4, 5, 6])
# print from a[1] to a[3], not including a[4](=5)
print(a[1:4])
[2 3 4]

2.2.3. Arithmetic operations on arrays#

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

# Addition
print(a + b)

# Subtraction
print(a - b)

# Multiplication
print(a * b)

# Division
print(a / b)
[ 6  8 10 12]
[-4 -4 -4 -4]
[ 5 12 21 32]
[0.2        0.33333333 0.42857143 0.5       ]
a = np.array([1, 2, 3, 4])

# Add a scalar to each element
print("a + 2 = ", a + 2)

# Subtract a scalar from each element
print("a - 2 = ", a - 2)

# Multiply a scalar to each element
print("a * 2 = ", a * 2)

# Divide each element by a scalar
print("a / 2 = ", a / 2)

# Take the square root of each element
print("a ** 0.5 = ", np.sqrt(a))

# Take the square of each element
print("a ** 2 = ", a**2)

# Take the log of each element
print("np.log(a) = ", np.log(a))

# Take the exponential of each element
print("np.exp(a) = ", np.exp(a))

# Take the sin of each element
print("np.sin(a) = ", np.sin(a))

# Take the cos of each element
print("np.cos(a) = ", np.cos(a))
a + 2 =  [3 4 5 6]
a - 2 =  [-1  0  1  2]
a * 2 =  [2 4 6 8]
a / 2 =  [0.5 1.  1.5 2. ]
a ** 0.5 =  [1.         1.41421356 1.73205081 2.        ]
a ** 2 =  [ 1  4  9 16]
np.log(a) =  [0.         0.69314718 1.09861229 1.38629436]
np.exp(a) =  [ 2.71828183  7.3890561  20.08553692 54.59815003]
np.sin(a) =  [ 0.84147098  0.90929743  0.14112001 -0.7568025 ]
np.cos(a) =  [ 0.54030231 -0.41614684 -0.9899925  -0.65364362]
a = np.array([1, 2, 3, 4, 5])

# Maximum
print("max = ", a.max())

# Minimum
print("min = ", a.min())

# Argmax
print("argmax = ", a.argmax())

# Argmin
print("argmin = ", a.argmin())

# Sum
print("sum = ", a.sum())

# Mean
print("mean = ", a.mean())

# Standard deviation
print("std = ", a.std())

# Variance
print("var = ", a.var())
max =  5
min =  1
argmax =  4
argmin =  0
sum =  15
mean =  3.0
std =  1.4142135623730951
var =  2.0
# Dot product
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
print(np.dot(a, b))
70

2.2.4. Matrix operations#

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

# Matrix multiplication
print(np.dot(a, b), end="\n\n")

print(a.dot(b), end="\n\n")

print(a @ b, end="\n\n")
[[ 58  64]
 [139 154]]

[[ 58  64]
 [139 154]]

[[ 58  64]
 [139 154]]
a = np.array([[1, 2, 3], [4, 6, 8], [7, 11, 13]])

# Transpose
print("a.T = ", a.T, sep="\n", end="\n\n")

# Trace
print("np.trace(a) = ", np.trace(a), end="\n\n")

# Determinant
print("np.linalg.det(a) = ", np.linalg.det(a), end="\n\n")

# Inverse
print("np.linalg.inv(a) = ", np.linalg.inv(a), sep="\n", end="\n\n")
a.T = 
[[ 1  4  7]
 [ 2  6 11]
 [ 3  8 13]]

np.trace(a) =  20

np.linalg.det(a) =  3.999999999999999

np.linalg.inv(a) = 
[[-2.5   1.75 -0.5 ]
 [ 1.   -2.    1.  ]
 [ 0.5   0.75 -0.5 ]]

np.linalg.??? is a module for linear algebra. linalg can also be called from scipy as scipy.linalg.???.

# Eigenvalues and eigenvectors
eigvals, eigvecs = np.linalg.eig(a)
print("eigvals = ", eigvals, sep="\n", end="\n\n")
print("eigvecs = ", eigvecs, sep="\n", end="\n\n")

print("a = ", eigvecs @ np.diag(eigvals) @ np.linalg.inv(eigvecs), sep="\n", end="\n\n")
eigvals = 
[20.96315698 -0.27883016 -0.68432682]

eigvecs = 
[[-0.17747914 -0.84842833 -0.74978668]
 [-0.50048229  0.52923643 -0.27279835]
 [-0.8473598   0.00884096  0.6028275 ]]

a = 
[[ 1.  2.  3.]
 [ 4.  6.  8.]
 [ 7. 11. 13.]]
# Singular value decomposition
U, S, V = np.linalg.svd(a)
print("U = ", U, sep="\n", end="\n\n")
print("S = ", S, sep="\n", end="\n\n")
print("V = ", V, sep="\n", end="\n\n")

print("a = ", U @ np.diag(S) @ V, sep="\n", end="\n\n")
U = 
[[-0.17104729  0.72829433  0.6635738 ]
 [-0.49727069  0.51761162 -0.69627586]
 [-0.85056727 -0.4490719   0.27362335]]

S = 
[21.64329507  0.70666899  0.26152943]

V = 
[[-0.37490137 -0.58595323 -0.71840641]
 [-0.48786982 -0.53424233  0.69033917]
 [-0.78830959  0.6092979  -0.08558071]]

a = 
[[ 1.  2.  3.]
 [ 4.  6.  8.]
 [ 7. 11. 13.]]

2.2.5. Learn more about numpy#