Skip to article frontmatterSkip to article content

Introduction to NumPy

Text provided under a Creative Commons Attribution license, CC-BY. All code is made available under the FSF-approved MIT license. (c) Kyle T. Mandli
from __future__ import print_function

Introduction to NumPy

NumPy is the basic library in Python that defines a number of essential data structures and routines for doing numerical computing (among other things). Many of the semantics for manipulating the most basic data structure, the ndarray, are identical to manipulating lists with a few key exceptions. Other commands are similar to matlab commands and work in a similar manner. We will cover those and some of the other important points when working with NumPy.

Topics:

  • The ndarray

  • Mathematical functions

  • Array manipulations

  • Common array functions

  • Math Functions in NumPy

ndarray

The ndarray forms the most basic type of data-structure for NumPy. As the name suggests the ndarray is an array that can have as many dimensions as you specify. For matlab users this should be familiar although note that the ndarray does not exactly behave as you might expect the same object to in matlab. Here are some examples usages:

import numpy

Define a 2x2 array, note that unlike MATLAB we need commas everywhere:

my_array = numpy.array([[1, 2], [3, 4]])
print(my_array)

Get the (0, 1) component of the array:

print(my_array)
my_array[0, 1]

Fetch the second row of the matrix:

my_array[1, :]

Fetch the first column of the matrix:

print(my_array)
my_array[:, 0]

Define a column vector:

my_vec = numpy.array([[1], [2]])
print(my_vec)
print("my vec has shape:{}".format(my_vec.shape))

Multiply my_array by the vector my_vec in the usual linear algebra sense (equivalent to MATLAB’s *)

print(my_array)
print(numpy.dot(my_array, my_vec))
print(my_array.dot(my_vec))

Multiply my_array and my_vec by “broadcasting” the matching dimensions, equivalent to MATLAB’s .* form:

print(my_array)
print()
print(my_vec)
my_array * my_vec

Common Array Constructors

Along with the most common constructor for ndarrays above (array) there are number of other ways to create arrays with particular values inserted in them. Here are a few that can be useful.

The linspace command (similar to MATLAB’s linspace command) take three arguments, the first define a range of values and the third how many points to put in between them. This is great if you want to evaluate a function at evently space points between two numbers.

print(numpy.linspace(-1, 1, 10))

Another useful set of functions are zeros and ones which create an array of zeros and ones respectively (again equivalent to the functions in MATLAB). Note that you can explicitly define the data type.

numpy.zeros([3, 3])
numpy.ones([3, 3, 2], dtype=int)

Another common array is the identity matrix. The identity command can be used to define an identity matrix of a given dimension.

I = numpy.identity(3)
print(I)

Note that NumPy arrays can be reshaped and expanded after they are created but this can be computational expense and may be difficult to fully understand the consequences of (reshape in particular can be difficult). One way to avoid these issues is to create an empty array of the right size and storing the calculated values as you find them. The array constructor to do this is called empty:

numpy.empty([2, 3])

Note that here the IPython notebook is displaying zeros (or something close to this). The values are almost always not zero but the display of values is truncated to help with displaying long numbers. This can be controlled using %precision 3 where 3 is upto the number of decimal points to display

%precision 3
numpy.empty([2, 3]) + 2

Array Manipulations

Sometimes, despite our best efforts, we will need to manipulate the size or shape of our already created arrays.

  • Note that these functions can be complex to use and can be computationally expensive so use sparingly!

  • That being said, often these can still be a great way to avoid using too much memory and still may be faster than creating multiple arrays.

  • Check out the NumPy Docs for more functions beyond these basic ones

One of the important aspects of an array is its shape.

A = numpy.array([[1, 2, 3], [4, 5, 6]])
print(A)
print("A Shape = ", A.shape)

We can reshape an array.

B = A.reshape((6, 1))
print("A Shape = ", A.shape)
print("B Shape = ", B.shape)
print(B)

Take the matrix A and make a larger matrix by tiling the old one the number of times specified.

A
B = numpy.tile(A, (2, 3))
print(B.shape)
B
A.flatten()

Array Operations

The numpy library also includes a number of basic operations on arrays. For example, a common operation is to determine the transpose of an array.

B = numpy.array([[1, 2, 3], [1, 4, 9], [1, 8, 27]])
print(B)
print(B.transpose())

One nice aspect of the numpy libary is that scalar multiplication is defined in the usual way.

v = numpy.array([[1], [2], [3]])
print(v)
print(2 * v)

Another common operation is to multiply two arrays. Be careful to make sure that an operation is defined. It is important to learn how to read and interpret error messages.

A = numpy.array([[1], [-1], [1]])
B = numpy.array([[1, 2, 3], [1, 4, 9], [1, 8, 27]])
print("A=\n{}".format(A))
print()
print("B=\n{}".format(B))
print(numpy.matmul(B, A))
print(numpy.matmul(A.transpose(), B))
print(numpy.matmul(A, B))
print(A * B)

Note: Matrix-Matrix (and by extension Matrix-vector) multiplication can also be done using the array method dot

print(B.dot(A))
print(A.transpose().dot(B))

An element within an array can be changed using the same notation above that is used to get the value of an entry within an array.

B = numpy.array([[1, 2, 3], [1, 4, 9], [1, 8, 27]])
print(B)
B[0, 0] = -5
print(B)

or even whole slices or sub-arrays can be changed

B[:, 1] = numpy.array([1, 2, 3])
print(B)

Mathematical Functions

Similar to the built-in Python module math, NumPy also provides a number of common math functions such as sqrt, sin, cos, and tan along with a number of useful constants, the most important of which is π\pi. The benefit of using NumPy’s versions is that they can be used on entire arrays.

x = numpy.linspace(-2.0 * numpy.pi, 2.0 * numpy.pi, 62)
print(x)
y = numpy.sin(x)
print(y)
import math

print(math.sin(x))

This is often useful for plotting functions easily or setting up a problem (we will cover plotting next).

import matplotlib.pyplot as plt

%matplotlib inline

fig = plt.figure(figsize=(8, 6))
plt.plot(x, y, linewidth=2)
plt.grid()
plt.xlabel("$x$", fontsize=16)
plt.ylabel("$y$", fontsize=16)
plt.title("$\sin{x}$", fontsize=18)
plt.show()

One thing to watch out for (and this is true of the math module) is that contrary to what you might expect:

x = numpy.linspace(-1, 1, 20)
print(x)
numpy.sqrt(x)

The problem is that if you take the sqrt of a negative number NumPy does not automatically use the Complex variable type to represent the output. Unlike lists, NumPy requires the data stored within to be uniform (of the same type or record structure). By default NumPy assumes we want floats which obey the IEEE compliant floating point rules for arithmetic (more on this later) and generates nans instead (nan stands for “not-a-number”, see more about this special value here).

If we want to deal with complex numbers there is still a way to tell NumPy that we want the Complex data type instead by doing the following:

x = numpy.linspace(-1, 1, 20, dtype=complex)
numpy.sqrt(x)
print(x)

There are number of other data types that NumPy understands, the most important one being int for integers.

Time for HW0

Homework 0 is a little, non-graded, assignment to test the grading system as well as your basic knowledge of

  • Markdown with LaTeX\LaTeX

  • python functions and a little numpy