In this blog, we will be learning more about NumPy Functions like Universal Functions, Sorting of Arrays, Broadcasting, and Indexing using python with a use-case. In our previous blog, we did discuss how NumPy and NumPy arrays can be used in python.

Refer to the below blog link to have a better understanding of NumPy basics:

Now, let us first understand Universal Function.

AÂ **U****niversal Function**Â is a function in NumPy that operates on nd-array, and which supports array broadcasting, type-casting, and other standard features. This means a ufunc(Universal function) supports vectorized operation, that can be accomplished by performing operations on the array, which will then be applied to each element.

Features:

- ufuncs are extremely flexible â€“ i.e., we can also operate between a scalar and an array.
- ufunc operations can act on one-dimensional arrays as well as multi-dimensional arrays.
- Computations using vectorization through ufuncs are more efficient than their counterpart implemented using Python loops.
- ufuncs exist in two flavors:Â
*unary ufuncs*, which operate on a single input, andÂ*binary ufuncs*, which operate on two inputs.

Use of Ufunc: Computations in NumPy can either be very fast or can be very slow. To make operations fast, they are generally implemented through NumPyâ€™s Universal Functions.

Starting with the Arithmetic Functions such as addition, subtraction, multiplication and division of array, we will follow the following steps:

- Arithmetic Functions:Â NumPyâ€™s ufuncs are very natural to use because they make use of Pythonâ€™s native arithmetic operators. The standard addition, subtraction, multiplication and division can be used.

Let us see this with the help of an example

import numpy as np a = np.array([2, 4, 8, 1]) # adding 2 to every element print ("Adding 2 to every element:", a+2) # subtracting 1 from each element print ("Subtracting 1 from each element:", a-1) # multiplying each element by 10 print ("Multiplying each element by 10:", a*10)

We can also modify an existing array by performing some more operations on it such as:

- Squaring each element
- Transposing a matrix
- Finding Max element of an array
- Finding Min element of an array
- Finding Sum of an array

To square each element of an array:

print ("Squaring each element:", a**2)

To print the transpose of a Matrix:

a = np.array([[5, 6, 7], [8, 9, 10], [21, 22, 23]]) print("Original Matrix \n ", a) print("Transpose of Matrix a \n ", a.T)

To fetch the max and min element of an array

x = np.array( [ [5, 8, 11], [4, 1, 9], [10, 12, 19]]) print ("Largest element is:", x.max()) print ("Row-wise maximum elements:", x.max(axis = 1)) print ("Smallest element is:", x.min()) print ("Column-wise smallest elements:", x.min(axis = 0)

In the above code, the first statement is to print the highest/smallest element of the array named x and the second statement is to print the highest/smallest element row-wise/column-wise.

Here we made use of axis, where axis = 0 means column wise and axis = 1 means row-wise.

To get the sum of an array

print ("Sum of all array elements:", x.sum())

Likewise, we can find the cumulative sum along each row

print ("Cumulative sum along each row:\n", x.cumsum(axis = 1))

Until now we have learned about some of theÂ **unary operator and functions**. Now we will read about some of theÂ **binary operators and functions**.

Binary operators are the one where 2 operators are being used.

Here we will perform addition, subtraction, multiplication of 2 arrays/matrices.

To perform addition, subtraction, and multiplication on 2 arrays

a = np.array( [ [1, 2], Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â [3, 4] ] ) b = np.array( [ [5, 6], Â Â Â Â Â Â Â Â Â Â Â Â Â Â [7, 8] ] ) print("Sum of 2 arrays \n", a+b) print("Difference of 2 arrays \n", a-b)

To perform array multiplication and matrix multiplication:

# multiply arrays print ("Array multiplication:\n", a*b)Â # matrix multiplication print ("Matrix multiplication:\n", a.dot(b))

From the above example, we can see that two operations were performed.

Array multiplication i.e, element-wise multiplication in which the first element of array â€˜aâ€™ gets multiplied to the first element of array â€˜bâ€™, the second element of array â€˜aâ€™ gets multiplied to the second element of array â€˜bâ€™ and so on.

And Matrix multiplication i.e., each row of array â€˜aâ€™ gets multiplied to each column of array â€˜bâ€™. Here we made use of the function dot().

These were the usage of some of the operators and functions.

Some of the others functions are listed below

add(),Â subtract(),Â negative(),Â multiply(),Â divide(),Â floor_divide(),Â power(),Â mod(),Â abs() etc.

- Trigonometric Functions:Â NumPy has standard trigonometric functions which are used to create trigonometric ratios of different angles in radians.

Consider the below code to understand the concept of sin, cos, tan:

arr = np.array([0, 30, 60, 90, 120, 150, 180]) x = arr * np.pi/180 print("\nThe sin value of the angles\n") Â print(np.sin(x)) Â print("\nThe cosine value of the angles\n") Â print(np.cos(x)) Â print("\nThe tangent value of the angles\n") Â print(np.tan(x))

Exponential:Â Another common type of operation available in a NumPy ufunc are the exponentials

Consider the following example:

x = [3, 4, 5] print("x Â Â Â Â =", x) print("e^x Â Â =", np.exp(x)) print("2^x Â Â =", np.exp2(x)) print("3^x Â Â =", np.power(3, x))

Logarithmic:Â The inverse of exponentials i.e, the logarithms, are also available. The function log() Â gives the natural logarithm

x = [2, 4, 6, 8] print("x Â Â Â Â Â Â Â =", x) print("ln(x) Â Â Â =", np.log(x)) print("log2(x) Â =", np.log2(x)) print("log10(x) =", np.log10(x))

**Sorting Arrays**

Sorting means arranging data in a systematic manner.

Until now we have seen examples of various operations being performed on an array. In this section, we will see how sorting of arrays is being done.

NumPyâ€™s sort() function is the most efficient and useful function which could serve our above purpose.

Let us see the working with the help of an example

x = np.array([2, 41, 14, 53, 25]) np.sort(x)

NumPyâ€™s argsort() function is one more function which returns the indices of the sorted elements.

x = np.array([2, 41, 14, 53, 25]) i = np.argsort(x) print(i)

In the result shown above the first element gives the index of the smallest array element, the second element gives the index of the second smallest array element and so on.

**Introduction to Broadcasting**

NumPy provides a powerful mechanism called Broadcasting. It is simply a set of rules for applying binary ufuncs(eg.: addition, subtraction, multiplication etc) on arrays of different size

A = np.array([ [11, 12, 13], Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â [21, 22, 23], Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â [31, 32, 33] ]) B = np.array([1, 2, 3]) print("Addition with broadcasting: ") print(A + B) print("Multiplication with broadcasting: ") print(A * B)

In the above code each element of array A is added to each element of array B row-wise. Likewise, for multiplication, each element of array A is multiplied to each element of array B row-wise.

**Introduction to Fancy Indexing**

When we have to access multiple elements at once we make use of Fancy Indexing. Fancy Indexing is conceptually simple, it means passing an array of indices to access multiple elements.

Let us see an example to understand this:

Consider the following array:

rand = np.random x = rand.randint(100, size=10) print(x)

If we want to access 3 different elements, we can do it as

[x[3], x[7], x[9]]

Or we can pass a single list of array of indices to obtain the same result

ind = [3, 7, 9] x[ind]

Fancy Indexing also works on the multi-dimensions array.

Consider the following array:

X = np.arange(9).reshape((3, 3)) X

To get the element from the array, we will make use of 2 parameters,Â the first index refers to the row, and the second to the column:

row = np.array([0, 1, 2]) col = np.array([2, 1, 1]) X[row, col]

As from the above example, we can see that the first element [2] is the result of the index [0, 2] that has been taken one from each variable.

**For Example:**Â Let us see how the above operations are performed on arrays and matrices with the help of some use cases

*Arithmetic Operation*

*Arithmetic Operation*

**Problem Statement 1: C****reate 3*3 matrices of random single-digit numbers and perform arithmetic operations on it such as addition, subtraction, multiplication, division, pow, etc.**

sol:

output:

the above program, we performed arithmetic operations such as addition, multiplication, division and square root using pow function.

*Universal functions*

*Universal functions*

**Problem Statement 1: C****reate 3*3 matrices of random single-digit numbers and apply universal functions on it such as square root, exponential, log10, Modulo etc.**

sol:

Output:

In the above program operations performed such as square root of matrix 1st by using function sqrt(), exponential power of all elements of Â matrix 1st (The exponential function is e^x where e is a mathematical constant called Eulerâ€™s number, approximately 2.718281 and x is the element of matrix 1st), logarithmic value of elements of matrix 1st and the modulo remainder i.e, the remainder on dividing matrix 1st by matrix 2nd.

*Broadcasting*

NumPyâ€™s broadcasting rule relaxes this constraint when the arraysâ€™ shapes meet certain constraints. When operating on two arrays, NumPy compares their shapes element-wise. It starts with the trailing dimensions and works its way forward. Two dimensions are compatible when they are equal, or one of them is 1.

**Problem Statement 1: C****reate 4*3 matrices of all zeroes and perform operations on it as given.**

**1.1: create a rank 1 ndarray with 3 values and add it to each row of â€˜arrâ€™ using broadcasting**

sol:

**1.2: create an ndarray which is 4 x 1 to broadcast across columns and add it to each column of â€˜arrâ€™ using broadcasting**

sol:

In the above program, we created an array of dimension 4*3 with all zeroes and perform specific operations on it.

Hope this post is helpful in understanding the working of NumPy and its various operations explained with the help of use cases.

In future, you can expect more blogs on Python libraries, until then Keep visiting our websiteÂ AcadgildÂ for more updates on Data Science and other technologies.