Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

NumPy - ufunc Introduction



NumPy Universal Functions (ufuncs)

Ufuncs, or universal functions, are functions in NumPy that apply operations element-wise on ndarrays. They act as vectorized wrappers for simple functions, meaning they can apply the same operation to each element in an array simultaneously, which is much faster than using traditional Python loops.

Common examples of ufuncs include basic arithmetic operations like addition, subtraction, multiplication, and division, as well as more complex functions like trigonometric, logarithmic, and exponential functions.

Creating and Using ufuncs

NumPy provides a wide range of built-in ufuncs for performing common operations. You can also create custom ufuncs using the numpy.frompyfunc() function, which allows you to turn a Python function into a ufunc. Let us explore how to use both built-in and custom ufuncs.

Example: Using Built-in ufuncs

In this example, we use the built-in ufunc numpy.add() to perform element-wise addition of two arrays −

import numpy as np

# Define two arrays
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# Use the built-in ufunc numpy.add to add the arrays
result = np.add(a, b)

print(result)

Following is the output obtained −

[5 7 9]

Example: Creating a Custom ufunc

In this example, we create a custom ufunc using the numpy.frompyfunc() function. This ufunc will perform element-wise multiplication of two arrays −

import numpy as np

# Define a Python function for multiplication
def multiply(x, y):
   return x * y

# Create a custom ufunc from the Python function
multiply_ufunc = np.frompyfunc(multiply, 2, 1)

# Define two arrays
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# Use the custom ufunc to multiply the arrays
result = multiply_ufunc(a, b)

print(result)

This will produce the following result −

[4 10 18]

Advantages of Using ufuncs

Using ufuncs in NumPy provides several advantages over traditional loop-based approaches, they are −

  • Performance: Ufuncs are highly optimized and can perform operations much faster than equivalent Python loops.
  • Vectorization: Ufuncs operate on entire arrays at once, eliminating the need for explicit loops and reducing the likelihood of errors.
  • Broadcasting: Ufuncs support broadcasting, allowing you to perform operations on arrays of different shapes in a flexible manner.
  • Flexibility: Ufuncs can handle a wide range of operations, from simple arithmetic to complex mathematical functions.

Broadcasting with ufuncs

Broadcasting is a feature of NumPy that allows ufuncs to operate on arrays of different shapes. When performing operations on arrays of different sizes, NumPy automatically broadcasts the smaller array across the larger array so that they have compatible shapes.

For example, you can add a scalar to an array, or add two arrays of different shapes, and NumPy will handle the broadcasting for you.

Example

In this example, we add a scalar to an array using broadcasting in NumPy −

import numpy as np

# Define an array
a = np.array([1, 2, 3])

# Add a scalar to the array using broadcasting
result = np.add(a, 5)

print(result)

Following is the output of the above code −

[6 7 8]

Commonly Used ufuncs in NumPy

NumPy provides a complete set of built-in ufuncs for performing various operations. Some of the most commonly used ufuncs are −

  • Arithmetic ufuncs: np.add(), np.subtract(), np.multiply(), np.divide()
  • Trigonometric ufuncs: np.sin(), np.cos(), np.tan(), np.arcsin(), np.arccos(), np.arctan()
  • Exponential and logarithmic ufuncs: np.exp(), np.log(), np.log10(), np.log2()
  • Comparison ufuncs: np.greater(), np.less(), np.equal(), np.not_equal()

Example: Using Trigonometric ufuncs

In this example, we use the trigonometric ufunc numpy.sin() to calculate the sine of each element in an array −

import numpy as np

# Define an array of angles in radians
angles = np.array([0, np.pi/2, np.pi])

# Use the trigonometric ufunc numpy.sin to calculate the sine of each angle
sine_values = np.sin(angles)

print(sine_values)

The output obtained is as shown below −

[0.0000000e+00 1.0000000e+00 1.2246468e-16]

Example: Using Exponential ufuncs

Here, we use the exponential ufunc numpy.exp() to calculate the exponential of all elements in the array −

import numpy as np

# array
arr = np.array([1, 2, 3])

# Calculate the exponential of each element
exp_result = np.exp(arr)

print("Exponential of each element:", exp_result)

After executing the above code, we get the following output −

Exponential of each element: [ 2.71828183  7.3890561  20.08553692]

Example: Using Logarithmic Ufunc

Now, we use the logarithmic ufunc numpy.log() to calculate the natural logarithm (base e) of all elements in the array −

import numpy as np

# array
arr = np.array([1, np.e, np.e**2])

# Calculate the natural logarithm of each element
log_result = np.log(arr)

print("Natural logarithm of each element:", log_result)

We get the output as shown below −

Natural logarithm of each element: [0. 1. 2.]

Example: Using Comparison Ufunc

In here, we use the comparison ufunc numpy.greater() that compares two arrays element-wise and returns a boolean array indicating where the elements of the first array are greater than those of the second array −

import numpy as np

# arrays
arr1 = np.array([1, 2, 3])
arr2 = np.array([2, 2, 2])

# Compare each element of arr1 with arr2
comparison_result = np.greater(arr1, arr2)

print("Comparison result (arr1 > arr2):", comparison_result)

The result produced is as follows −

Comparison result (arr1 > arr2): [False False  True]
Advertisements