NumPy – Arithmetic, Indexing, Shape Manipulation

This page covers NumPy’s basic operations – Array Arithmetic, Array Indexing and Slicing, and Array Shape Manipulation.  These operations constitute the basic building blocks in developing programs for scientific applications, linear algebra, and machine learning.

NumPy provides a powerful way to perform arithmetic operations on arrays. You can perform arithmetic operations like addition, subtraction, multiplication, and division on arrays. In NumPy, arithmetic operators apply elementwise. meaning each element in one array is operated on by the corresponding element in another array.

These operations can also be performed between an array and a single number. The single number applies the operation to every element in the array.

The operation returns a new array filled with the result.

In the following examples, “arr1” and “arr2” are the two arrays to be operated on.

Sum: Sums corresponding elements of two arrays.

Syntax: np.add(arr1, arr2)

Difference: Subtracts elements of the second array from the first.

Syntax: np.subtract(arr1, arr2)

print("PROGRAM NAME : sum_difference.py")
# NUmPy sum and difference operations
import numpy as np
arr1 = np.array([10, 5, -4, 7])
arr2 = np.array([5, 2, -1, 3])
sum = np.add(arr1, arr2)
print("The sum of arr1 and arr2 is : /n", sum)
print()
difference = np.subtract(arr1, arr2)
print("The difference of arr1 and arr2 is : \n" , difference)
print()
#2D Array addition and suntraction
arr3 = np.array([[4, 5], [7, 8]])
arr4= np.array([[2, 7], [5, -7]])
sum2d = np.add(arr3, arr4)
print("The sum of arr3 and arr4 is : /n", sum2d)
print()
difference2d = np.subtract(arr3, arr4)
print("The difference of arr3 and arr4 is : \n" , difference2d)

The following is the program’s output.

PROGRAM NAME : sum_difference.py
The sum of arr1 and arr2 is : /n [15 7 -5 10]

The difference of arr1 and arr2 is :
[ 5 3 -3 4]

The sum of arr3 and arr4 is : /n [[ 6 12]
[12 1]]

The difference of arr3 and arr4 is :
[[ 2 -2]
[ 2 15]]

The product operator (*) applies elementwise in NumPy arrays. Scalar multiplication involves multiplying each element of an array by a single number (scalar). You can achieve this using the * operator or the np.multiply() function, both of which will yield the same result.


#Multiply an array by a scalar
import numpy as np
arr1 = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
scalar = 2
result = arr1 * scalar
print("product of scalar and arr1 = \n", result)
result2 = scalar * np.sin(arr1)
print("product of scalar and sin(arr1) = \n", result2)
result3 = scalar * np.cos(arr1)
print("product of scalar and cos(arr1) = \n", result3)

The following is the result of the program.

product of scalar and arr1 =
[0. 1.04719755 1.57079633 2.0943951 3.14159265]
product of scalar and sin(arr1) =
[0. 1. 1.41421356 1.73205081 2. ]
product of scalar and cos(arr1) =
[2.00000000e+00 1.73205081e+00 1.41421356e+00 1.00000000e+00
1.22464680e-16]

The Multiply operator multiplies corresponding elements of two arrays. The product operator * operates elementwise in NumPy arrays.

Element-wise multiplication involves multiplying corresponding elements of two arrays of the same shape. This can be done using:

  • The np.multiply() function
  • The * operator
# Multiply two arrays element-wise
import numpy as np
arr1 = np.array([[2, 3], [4, 5]])
arr2 = np.array([[6, 7], [8, 9]])
product = arr1 * arr2 # Element-wise product
print("Element-wise product of arr1 and arr2 = \n", product)

The output of the above program is:

Element-wise product of arr1 and arr2 =
[[12 21]
[32 45]]

Divide operator divides elements of the first array by the corresponding elements of the second array. NumPy division is performed using the numpy.divide() function, which allows for element-wise division of arrays. The / operator can be used as a shorthand for np.divide on ndarrays.

Syntax: np.divide(x1, x2, out)

  • x1: The first input array.
  • x2: The second input array or a scalar.
  • out: Specify an output array to store the result.

The quotient x1/x2 is calculated element-wise. The quotient is a scalar if both x1 and x2 are scalars.

numpy.divide() Returns ndarray or scalar.

# Division of two NumPy arrays
import numpy as np
arr1 = np.array([[10, 20], [30, 40]])
arr2 = np.array([[2, 4], [5, 8]])
quotient = arr1 / arr2 # Element-wise division
print("Element-wise quotient of arr1 and arr2 = \n", quotient)
quotient1 = np.divide(arr1, arr2) # Using np.divide function
print("Element-wise quotient of arr1 and arr2 using np.divide = \n", quotient1)

The outpout of the program is below:

Element-wise quotient of arr1 and arr2 =
[[5. 5.]
[6. 5.]]
Element-wise quotient of arr1 and arr2 using np.divide =
[[5. 5.]
[6. 5.]]

Modulo operator returns the remainder of the division of the corresponding elements of the two arrays. It is used to perform the modulo operation, which calculates the remainder after dividing each element in the first array by the corresponding element in the second array. numpy.mod(), returns the element-wise remainder of division for two arrays

Syntax: numpy.mod(x1, x2, /, out=None)

  • x1: The first input array.
  • x2: The second input array or a scalar.
  • out: Optional; a location into which the result is stored.
# Numpy Modulo function
import numpy as np
def np_modulo(x1, x2):
    return np.mod(x1, x2)
# Example usage
x1 = np.array([10, 20, 30])
x2 = np.array([3, 4, 5])
result = np_modulo(x1, x2)
print("Element-wise modulo of x1 and x2 = \n", result)
# Numpy Remainder function
def np_remainder(x1, x2):
    return np.remainder(x1, x2)
# Example usage
x1 = np.array([10, 20, 30])
x2 = np.array([3, 4, 5])
result = np_remainder(x1, x2)
print("Element-wise remainder of x1 and x2 = \n", result)

The following is the program’s output:

Element-wise modulo of x1 and x2 =
[1 0 0]
Element-wise remainder of x1 and x2 =
[1 0 0]

NumPy provides a powerful function called power() that allows users to perform exponentiation on arrays and individual numbers efficiently.

numpy.power() function raises elements of the first array to the power of the corresponding element in the second array,handling both single numbers and arrays efficiently.

Arrays or scalars can be used for both the base and the exponent.

NumPy’s power() function performs calculations element-wise.

Syntax: numpy.power(base, exponent, out=None, where=True)

ParameterDescription
BaseElements of the first array
ExponentElements of the second array
Outout: Loction to store the result in an array (optional)
whereoptional
# Numpy Exponential function
import numpy as np
arr1 = np.array([9, 2, 3, 4]) # Base array
arr2 = np.array([0.5, 1.2, 1.5, 2.0]) # Exponent array
result = np.power(arr1, arr2)
print("arr1 raised to the power of arr2 is = \n", result)

The following is the programs’s output:

arr1 raised to the power of arr2 is =
[ 3. 2.29739671 5.19615242 16. ]

Unary operations in NumPy are functions that operate on a single input. These operations are essential for performing calculations on individual elements of an array.

Many unary operations, such as computing the sum of all the elements in the array, are implemented as methods of the ndarray class.

Common Unary Operations

OperationFunctionDescription
Negationnp.negative()Returns the negation of each element in the array.
Square Rootnp.sqrt()Computes the square root of each element.
Exponentialnp.exp()Calculates the exponential (e^x) of each element.
Absolute Valuenp.abs()Returns the absolute value of each element.
Natural Logarithmnp.log()Computes the natural logarithm of each element.
Base-10 Logarithmnp.log10()Computes the logarithm to the base 10 of each element.
# NumPy Unary Operations
import numpy as np
# Create a NumPy array
arr1 = np.array([np.pi/3, np.pi/4, 2, np.pi/6])
# Calculate the square root of each element
sqrt_arr = np.sqrt(arr1)
print("Square root of each element:\n", sqrt_arr)
# Calculate the exponential of each element
exp_arr = np.exp(arr1)
print("Exponential of each element:\n", exp_arr)
# Calculate the natural logarithm of each element
log_arr = np.log(arr1)
print("Natural logarithm of each element:\n", log_arr)
# Calculate the absolute value of each element
abs_arr = np.abs(arr1)
print("Absolute value of each element:\n", abs_arr)
# Calculate the sine of each element
sin_arr = np.sin(arr1)
print("Sine of each element:\n", sin_arr)
# Calculate the cosine of each element
cos_arr = np.cos(arr1)
print("Cosine of each element:\n", cos_arr)
# Calculate the tangent of each element
tan_arr = np.tan(arr1)
print("Tangent of each element:\n", tan_arr)
# Calculate the sign of each element
sign_arr = np.sign(arr1)    
print("Sign of each element:\n", sign_arr)
# Calculate the reciprocal of each element
reciprocal_arr = np.reciprocal(arr1)
print("Reciprocal of each element:\n", reciprocal_arr)

The following is the program’s output:

Square root of each element:
[1.02332671 0.88622693 1.41421356 0.72360125]
Exponential of each element:
[2.84965391 2.19328005 7.3890561 1.68809179]
Natural logarithm of each element:
[ 0.0461176 -0.24156448 0.69314718 -0.64702958]
Absolute value of each element:
[1.04719755 0.78539816 2. 0.52359878]
Sine of each element:
[0.8660254 0.70710678 0.90929743 0.5 ]
Cosine of each element:
[ 0.5 0.70710678 -0.41614684 0.8660254 ]
Tangent of each element:
[ 1.73205081 1. -2.18503986 0.57735027]
Sign of each element:
[1. 1. 1. 1.]
Reciprocal of each element:
[0.95492966 1.27323954 0.5 1.90985932]

Most scientific and methematical computations make extensive use of Linear Algebra concepts. Discussion of detailed Linear Algebra is beyond the scope of this website. However, a brief glimpse into some of the Linear Algebra functions would be helpful.

The @ operator in NumPy is used for matrix multiplication, allowing you to perform dot product operations between two matrices or a matrix and a vector. It provides a concise and readable way to multiply arrays.

The number of columns in the first matrix must equal the number of rows in the second matrix. Here is a simple code to multiply matrix_a and matrix_b.

result = matrix_a @ matrix_b

Advantages of @ operator:

The @ Operator simplifies the syntax. The code is easier to read and understand.

Using the @ operator is a straightforward way to handle matrix multiplication in NumPy, enhancing both performance and readability in your code.

The dot product of matrices is defined as follows:

  • For each element in the resulting matrix, take a row from the first matrix and a column from the second matrix.
  • Multiply the corresponding elements.
  • Sum these products to get the value for that position in the resulting matrix.

How dot product of matrices is calculated.

In the program example below (matrix_a x matrix_b), if dot product matrix is

[c11 c12

c21 c22]

Then c11 = [1 x 5 + 2 X 7] = 19

And c12 = [1 X 6 + 2 X 8] = 22

And so on.

Program Example: Matrix Multiplication Using the @ Operator

print("The @ operator example")

import numpy as np
#define matrices.  Matrix_a and matrix_b are 2x2 matrices
matrix_a = np.array([[1, 2], 
                     [3, 4]])

matrix_b = np.array([[5, 6], 
                     [7, 8]])
# Multiply matrix_a and matrix_b using the @ operator
# and save the product in "result".
dot_product = matrix_a @ matrix_b
print("The dot product of matrix_a and matrix_b is: \n", dot_product)

The following is the output of the program:

The @ operator example
The dot product of matrix_a and matrix_b is:
[[19 22]
[43 50]]

Different Multiply Operators

The product operator * operates elementwise in NumPy arrays. The matrix product can be performed using the @ operator or the dot function or method:

Summary of Matrix Operations with NumPy

OperationFunction/OperatorDescription
Matrix Multiplication@ or np.matmul()Multiplies two matrices to produce a product.
Element-wise Multiplication*Multiplies corresponding elements of matrices.
Dot Productnp.dot()Computes the dot product of two arrays.

The program below shows the difference between the @ operator, * operator and dot product operator.

# The @, *, and dot operators
print("Program Name: Different multipliplication_operators.py \n")
import numpy as np
# create two 2_D arrays arr1 and arr2
arr1 = np.array([[1,2], [0, 1]])
arr2 = np.array([[2, 4], [3, 5]])
# Perform element-wise multiplication (* operator) of arrays 'arr1' and 'arr2'
product_element_wise = arr1 * arr2
print("Element-wise mutiplication of 'arr1' and 'arr2' (* operator) result is:")
print(product_element_wise)
print("End of Element-wise multiplication section. \n")
# Perform matrix multiplication of arrays arr1 and arr2 (the @ operator)
matrixproduct = arr1 @ arr2
print("matrix multiplication result of 'arr1' and 'arr2' (# operator) is:")
print(matrixproduct)
print("End of matrix multiplication section. \n")
# Dot product multiplication
dotproduct = arr1.dot(arr2)
print("dot product multiplication result of 'arr1' and 'arr2' is: \n", dotproduct)

The following is the output of the program:

Program Name: Different multipliplication_operators.py

Element-wise mutiplication of ‘arr1’ and ‘arr2’ (* operator) result is:
[[2 8]
[0 5]]
End of Element-wise multiplication section.

matrix multiplication result of ‘arr1’ and ‘arr2’ (# operator) is:
[[ 8 14]
[ 3 5]]
End of matrix multiplication section.

dot product multiplication result of ‘arr1’ and ‘arr2’ is:
[[ 8 14]
[ 3 5]]

Verified by MonsterInsights