NumPy Fundamentals For Beginners
By: Bhanu Soni
Tags: Machine Learning, Python, Numpy, Data Science, Pandas

NumPy Fundamentals For Beginners

Getting started with NumPy, a scientific computing package in Python

What is NumPy?

NumPy is the fundamental package for scientific computing in Python. It is a Python library that provides a multidimensional array object, various derived objects (such as masked arrays and matrices), and an assortment of routines for fast operations on arrays, including mathematical, logical, shape manipulation, sorting, selecting, I/O, discrete Fourier transforms, basic linear algebra, basic statistical operations, random simulation and much more.

NumPy array object

NumPy has a multi-dimensional array object called ndarray. It consists of two parts:

The actual data Some metadata describing the data

The majority of array operations leave the raw data untouched. The only aspect that changes is the metadata.

The NumPy array is homogeneous — the items in the array have to be of the same type. The advantage is that, if we know that the items in the array are of the same type, then it is easy to determine the storage size required for the array.

NumPy arrays are indexed just like in Python, starting from 0. Data types are represented by special objects.

Let’s know what is arange function? numpy.arange Return evenly spaced values within a given interval. Values are generated within the half-open interval [start, stop) (in other words, the interval including start but excluding stop). For integer arguments, the function is equivalent to the Python built-in range function but returns an ndarray rather than a list.

numpy.arange([start, ]stop, [step, ]dtype=None) For example np.arange(3)

out: array([0, 1, 2]) np.arange(3,7,2)

out: array([3, 5])

We will create an array with the arange function again. Here’s how to get the data type of an array:

In: a = arange(5)

In: a.dtype

Out: dtype(‘int64’)

The data type of array a is int64 (at least on my machine), but you may get int32 as output if you are using 32-bit Python. In both cases, we are dealing with integers (64-bit or 32-bit). Besides the data type of an array, it is important to know its shape. The following diagram will give us a better understanding of a NumPy array object:

A vector is commonly used in mathematics but, most of the time, we need higher-dimensional objects. Let’s determine the shape of the vector we created a few minutes ago:

In [4]: a

Out[4]: array([0, 1, 2, 3, 4])

In: a.shape

Out: (5,)

As you can see, the vector has five elements with values ranging from 0 to 4. The shape attribute of the array is a tuple, in this case, a tuple of 1 element, which contains the length in each dimension.

Time for action — creating a multidimensional array

Now that we know how to create a vector, we are ready to create a multidimensional NumPy array. After we create the matrix, we would again want to display its shape and data type.

Create a multidimensional array.

In: m = array([arange(2), arange(2)])

In: m

Out:

array([[0, 1],

[0, 1]])

2. Show the array shape and data type:

In: m.shape

Out: (2, 2)

What just happened?

We created a 2-by-2 array with the arange function we have come to trust and love. Without any warning, the array function appeared on the stage.

The array function creates an array from an object that you give to it. The object needs to be array-like, for instance, a Python list. In the preceding example, we passed in a list of arrays. The object is the only required argument of the array function. NumPy functions tend to have a lot of optional arguments with predefined defaults.

Selecting elements

From time to time, we will want to select a particular element of an array. We will take a look at how to do this, but first, let’s create a 2-by-2 matrix again:

In: a = array([[1,2],[3,4]])

In: a

Out:

array([[1, 2],

[3, 4]])

The matrix was created this time by passing the array function a list of lists. We will now select each item of the matrix one-by-one. Remember, the indices are numbered starting from 0.

In: a[0,0]

Out: 1

In: a[0,1]

Out: 2

In: a[1,0]

Out: 3

In: a[1,1]

Out: 4

As you can see, selecting elements of the array is pretty simple. For the array a, we just use the notation a[m,n], where m and n are the indices of the item in the array.

NumPy numerical types

Python has an integer type, a float type, and a complex type, however, this is not enough for scientific computing and, for this reason, NumPy has a lot more data types. In practice, we need even more types with varying precision and, therefore, the different memory size of the type. The majority of the NumPy numerical types end with a number. This number indicates the number of bits associated with the type. The following table (adapted from the NumPy user guide) gives an overview of NumPy numerical types:

For each data type, there exists a corresponding conversion function:

In: float64(42)

Out: 42.0

In: int8(42.0)

Out: 42

In: bool(42)

Out: True

In: bool(42.0)

Out: True

In: float(True)

Out: 1.0

Many functions have a data type argument, which is often optional:

In: arange(7, dtype=uint16)

Out: array([0, 1, 2, 3, 4, 5, 6], dtype=uint16)

It is important to know that you are not allowed to convert a complex number into an integer. Trying to do that triggers a TypeError. This is shown as follows:

In: int(42.0 + 1.j)

--------------------------------------------------------------------

TypeError

Traceback (most recent call last)

TypeError: can't convert complex to int; use int(abs(z))

The same goes for the conversion of a complex number into a float. By the way, the .j part is the imaginary coefficient of the complex number. See the following code:

In: float(42.0 + 1.j)

--------------------------------------------------------------------

TypeError

Traceback (most recent call last)

TypeError: can't convert complex to float; use abs(z)

Data type objects

Data type objects are instances of the numpy.dtype class. Once again, arrays have a data type. To be precise, every element in a NumPy array has the same data type. The data type object can tell you the size of the data in bytes. The size in bytes is given by the itemsize attribute of the dtype class:

In: a.dtype.itemsize

Out: 8

The following diagram gives us a better understanding of data type objects:

Character codes

Character codes are included for backward compatibility with Numeric. Numeric is the predecessor of NumPy. Their use is not recommended, but the codes are provided here because they pop up in several places. You should instead use dtype objects.

Look at the following code to create an array of single precision floats:

In: arange(7, dtype='f')

Out: array([ 0., 1., 2., 3., 4., 5., 6.], dtype=float32) Likewise this creates an array of complex numbers In: arange(7, dtype='D')

Out: array([ 0.+0.j, 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j, 5.+0.j,6.+0.j])

dtype constructors

We have a variety of ways to create data types. Take the case of floating-point data:

We can use the general Python float:

In: dtype(float)

Out: dtype('float64')

2. We can specify a single-precision float with a character code:

In: dtype('f')

Out: dtype('float32')

3. We can use a double-precision float character code:

In: dtype('d')

Out: dtype('float64')

4. We can give the data type constructor a two-character code. The first character signifies the type; the second character is a number specifying the number of bytes in the type:

In: dtype('f8')

Out: dtype('float64')

A listing of all full data type names can be found in sctypeDict.keys() :

In: dtype('Float64')

Out: dtype('float64'

dtype attributes

The dtype class has a number of useful attributes. For example, we can get information about the character code of a data type through the attributes of dtype :

In: t = dtype('Float64')

In: t.char

Out: 'd'

The type attribute corresponds to the type of object of the array elements:

In: t.type

Out: <type 'numpy.float64'>

The str attribute of dtype gives a string representation of the data type. It starts with a character representing endianness, if appropriate, then a character code, followed by a number corresponding to the number of bytes that each array item requires.

Endianness, here, means the way bytes are ordered within a 32 or 64-bit word. In big-endian order, the most significant byte is stored first. In little-endian order, the least significant byte is stored

first.

In: t.str

Out: '<f8'

Creating a record data type

The record data type is a heterogeneous data type — think of it as representing a row in a spreadsheet or a database. To give an example of a record data type, we will create a record for a shop inventory. The record contains the name of the item, a 40-character string, the number of items in the store represented by a 32-bit integer and, finally, a price represented by a 32-bit float. The following steps show how to create a record data type:

Create the record:

In: t = dtype([('name', str_, 40), ('numitems', int32), ('price',

float32)]) In: t

Out: dtype([('name', '|S40'), ('numitems', '<i4'), ('price','<f4')])

2. View the type (we can view the type of a field as well):

In: t['name']

Out: dtype('|S40')

If you don’t give the array function a data type, it will assume that it is dealing with floating-point numbers. To create the array now, we really have to specify the data type; otherwise, we will get a TypeError :

In: itemz = array([('Meaning of life DVD', 42, 3.14), ('Butter', 13,

2.72)], dtype=t)

In: itemz[1]

Out: ('Butter', 13, 2.7200000286102295)

What just happened?

We created a record data type, which is a heterogeneous data type. The record contained a name as a character string, a number as an integer and a price represented by a float.

Summary

The topics we covered in this article were: Data types, Array types, Type conversions, and Array creation.

Next, we will look at: Indexing, Slicing, and Shape manipulation.