Intro to NumPy for Calculus (markdown)#
By Raheem Mir
When it comes numerical computation, NumPy is the Python package / library of choice, offering performance and lots of functionality, making it a powerful tool for doing calculus.
Getting Started With NumPy#
To begin using NumPy, we start by “importing” the library:
import numpy as np
import numpy as np
loads in NumPy for us to use. We give it the shorthand name np
, meaning every time we call something from NumPy, we prefix it with np.
. This is a good way to keep things organized when we are working with multiple libraries.
NumPy implements many of the common mathematical functions, like trigonometric functions, logarithms and more:
np.sin(0)
np.pi/4
np.tan(np.pi/4)
np.arctan(1)
np.e
np.log(np.e) #np.log is the natural logarithm, NumPy also offers base 10 and base 2 logarithms
Working with Arrays#
The defining feature of NumPy is the NumPy array, a powerful data structure optimized for numerical computation. Think of them as the Python lists we’ve seen before (in Intro to Python for Calculus), but significantly more efficient and powerful, well suited for performing calculus tasks. Additionally, the many mathematical functions (as well as others) implemented in NumPy can be directly applied to arrays without the need for loops (less code, more functionality).
Creating a NumPy array is straightforward, generally we use the np.array()
function:
primes = np.array([2,3,5,7,11,13]) # creating an array of prime numbers
print(primes)
NumPy also provides specialized functions for creating arrays, one of them being np.linspace()
, which generates a set of evenly spaced values over a given interval (inclusive). This function is particularly useful for calculus tasks, from generating \(x\)-values to plot a function, to defining intervals for numerical approximations like Riemann sums.
The syntax is as follows:
np.linspace(a, b, N)
a
is the beginning of the interval, while b
is the end of the interval.
N
specifies the number of values to generate in between a
and b
.
Here we create a NumPy array of 11 evenly spaced values between 0 and 1:
x = np.linspace(0, 1, 11)
print(x)
Like with lists, we can access individual elements of a NumPy array by specifying their index, which starts at 0 (i.e. the first element is at index 0).
Here’s how we would access (and output) the first two elements of the array x
:
print(x[0], x[1])
To access elements from the end of an array, we use negative indices. For instance, [-1]
would specify the last index of an array.
Below is how we would access the last three elements of x
:
print(x[-3], x[-2], x[-1])
Using a colon :
inside the []
allows us to select a range of elements from an array, which is known as “slicing”. For example, x[:]
would access the entire array:
x[:] # retrieves all the elements of the array
To retrieve the entries after a certain index, we would place the :
to the right of the index value inside the []
:
x[2:] # outputs the elements from the third index onwards
To retrieve the entries before a particular index, we would place the :
to the left of the index value inside the []
:
x[:7] # outputs the first 7 elements
We can also explicitly state the starting and ending index of what we want to access:
x[3:8] # Retrieves elements from index 3 up to, but not including, index 8
Although we’ll most often be using np.linspace()
for our NumPy arrays, here is a brief overview of some of the other functions available:
np.arange(a, b, step)
generates a NumPy array with values starting at a
up to, but not including, b
. The step
parameter let’s you control the difference between consecutive values in the array.
np.ones(N)
generates an array of only 1’s, with a length of N.
np.zeros(N)
is similar to np.ones()
, generating an array of only 0’s, with a length of N.
even_numbers = np.arange(0, 20, 2)
print(even_numbers)
ones = np.ones(10)
print(ones)
zeros = np.zeros(20)
print(zeros)
Plotting With NumPy and Matplotlib#
We can use NumPy in conjunction with Matplotlib, the popular Python plotting library, to visualize functions.
First, we have to import Matplotlib, in particular, its pyplot
module:
import matplotlib.pyplot as plt
Here is the general framework for creating a basic plot:
Generating \(x\) values: This often involves using the
np.linspace()
function.Generating \(y\) values: This typically includes defining or using a function to compute the
y
values.Creating the plot: Call the
plt.plot()
function, passing in the \(x\) and \(y\) values, to create the plot.Customize the plot (Optional): Use additional Matplotlib functions, such as
plt.xlabel()
, orplt.grid()
, to customize the plot.Displaying the plot: Use the
plt.show()
function to display the plot. In a Jupyter Notebook environment, this step is not neccessary, as plots display automatically when you callplt.plot()
. However, it is still recommended to useplt.show()
, for a cleaner output and proper rendering.
Now let’s plot \(\cos(x)\) over the interval \([-2\pi, 2\pi]\):
First, let’s generate our \(x\)-values using np.linspace()
:
x1 = np.linspace(-2*np.pi, 2*np.pi, 100)
Next, we can define \(y\) as a function \(x\) using NumPy’s np.cos()
function:
y1 = np.cos(x1)
Now we can create and display our plot, passing in our \(x\) and \(y\) values to the plt.plot()
function, as well as calling the plt.show()
function to display it. You’ll notice that we’ve added some axis labels as well.
plt.plot(x1,y1) # creating the plot
plt.xlabel('x')
plt.ylabel('cos(x)')
plt.show() # displaying the plot
Now, let’s try plotting the function \(f(x) = x^3 - x^2 -x + 1\) over the interval \([-5, 5]\):
First, let’s generate our \(x\)-values with np.linspace()
:
x2 = np.linspace(-5, 5, 500)
Next, let’s define the function we want to plot and generate our \(y\)-values:
def f(x):
return x**3 - x**2 - x + 1
y2 = f(x2)
To create and display the plot, we use the plt.plot()
and plt.show()
functions:
plt.plot(x2,y2) # creating the plot
plt.xlabel('x')
plt.ylabel('f(x)')
plt.show()