Reader small image

You're reading from  Scientific Computing with Python 3

Product typeBook
Published inDec 2016
Reading LevelBeginner
PublisherPackt
ISBN-139781786463517
Edition1st Edition
Languages
Right arrow
Authors (3):
Claus Führer
Claus Führer
author image
Claus Führer

Claus Führer is a professor of scientific computations at Lund University, Sweden. He has an extensive teaching record that includes intensive programming courses in numerical analysis and engineering mathematics across various levels in many different countries and teaching environments. Claus also develops numerical software in research collaboration with industry and received Lund University's Faculty of Engineering Best Teacher Award in 2016.
Read more about Claus Führer

View More author details
Right arrow

Chapter 5. Advanced Array Concepts

In this chapter, we will explain some more advanced aspects of arrays. First, we will cover the notion of an array view, followed by Boolean arrays and how to compare arrays. We briefly describe indexing and vectorization, explain sparse arrays, and some special topics such as broadcasting.

Array views and copies


In order to control precisely how memory is used, NumPy offers the concept of view of an array. Views are smaller arrays that share the same data as a larger array. This works just like a reference to one single object (refer to section Basic Types in Chapter 1, Getting Started).

Array views

The simplest example of a view is given by a slice of an array:

M = array([[1.,2.],[3.,4.]])
v = M[0,:] # first row of M

The preceding slice is a view of M. It shares the same data as M. Modifying v will modify M as well:

v[-1] = 0.
v # array([[1.,0.]])
M # array([[1.,0.],[3.,4.]]) # M is modified as well

It is possible to access the object that owns the data using the array attribute base:

v.base # array([[1.,0.],[3.,4.]])
v.base is M # True

If an array owns its data, the attribute base is none :

M.base # None

Slices as views

There are precise rules on which slices will return views and which ones will return copies. Only basic slices (mainly index expressions with :...

Comparing arrays


Comparing two arrays is not as simple as it may seem. Consider the following code, which is intended to check whether two matrices are close to each other:

A = array([0.,0.])
B = array([0.,0.])
if abs(B-A) < 1e-10: # an exception is raised here
    print("The two arrays are close enough")

This code raises the exception when the if statement is executed:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

In this section, we explain why this is so and how to remedy this state of affairs.

Boolean arrays

Boolean arrays are useful for advanced array indexing (refer to section Indexing with Boolean arrays). A Boolean array is simply an array for which the entries have the type bool:

A = array([True,False]) # Boolean array
A.dtype # dtype('bool')

Any comparison operator acting on arrays will create a Boolean array instead of a simple Boolean:

M = array([[2, 3],
           [1, 4]])
M > 2 # array([[False...

Boolean operations on arrays


You cannot use andor, and not on Boolean arrays. Indeed, those operators force the casting from array to Boolean, which is not permitted. Instead, we can use the operators given in the following table (Table 5.1) for componentwise logical operations on Boolean arrays:

Logic operator

Replacement for Boolean arrays

A and B

A & B

A or B

A | B

not A

~ A

Table 5.1 Logical operators and, or and not do not work with arrays.

A = array([True, True, False, False])
B = array([True, False, True, False])
A and B # error!
A & B # array([True, False, False, False])
A | B # array([True, True, True, False])
~A # array([False, False, True, True])

Here is an example usage of logical operators with Boolean arrays:

Suppose that we have a sequence of data that is marred with some measurement error. Suppose further that we run a regression and it gives us a deviation for each value. We wish to obtain all the exceptional...

Array indexing


We have already seen that one may index arrays by combinations of slices and integers, this is the basic slicing technique. There are, however, many more possibilities, which allow for a variety of ways to access and modify array elements.

Indexing with Boolean arrays

It is often useful to access and modify only parts of an array, depending on its value. For instance, one might want to access all the positive elements of an array. This turns out to be possible using Boolean arrays, which act like masks to select only some elements of an array. The result of such an indexing is always a vector. For instance, consider the following example:

B = array([[True, False],
           [False, True]])
M = array([[2, 3],
           [1, 4]])
M[B] # array([2,4]), a vector

In fact, the M[B] call is equivalent to M.flatten()[B]. One may then replace the resulting vector by another vector. For instance, one may replace all the elements by zero (refer to section Broadcasting...

Performance and Vectorization


When it comes to performance of your Python code, it often boils down to the difference between interpreted code and compiled code. Python is an interpreted programming language and basic Python code is executed directly without any intermediate compilation to machine code. With a compiled language, the code needs to be translated to machine instructions before execution.

The benefits of an interpreted language are many but interpreted code cannot compete with compiled code for speed. To make your code faster, you can write some parts in a compiled language like FORTRAN, C, or C++. This is what NumPy and SciPy do.

For this reason, it is best to use functions in NumPy and SciPy over interpreted versions whenever possible. NumPy array operations such as matrix multiplication, matrix-vector multiplication, matrix factorization, scalar products, and so on are much faster than any pure Python equivalent. Consider the simple case of scalar products. The scalar product...

Broadcasting


Broadcasting in NumPy denotes the ability to guess a common, compatible shape between two arrays. For instance, when adding a vector (one-dimensional array) and a scalar (zero-dimensional array), the scalar is extended to a vector, in order to allow for the addition. The general mechanism is called broadcasting. We will first review that mechanism from a mathematical point of view, and then proceed to give the precise rules for broadcasting in NumPy.

Mathematical view

Broadcasting is often performed in mathematics, mainly implicitly. Examples are expressions such as f(x) + C or f(x) + g(y). We'll give an explicit description of that technique in this section.

We have in mind the very close relationship between functions and NumPy arrays, as described in section Mathematical preliminaries of Chapter 4, Linear Algebra - Arrays.

Constant functions

One of the most common examples of broadcasting is the addition of a function and a constant; if C is a scalar, one often writes:

This...

Sparse matrices


Matrices with a small number of nonzero entries are called sparse matrices. Sparse matrices occur, for example, in scientific computing when describing discrete differential operators in the context of numerically solving partial differential equations.

Sparse matrices often have large dimensions, sometimes so large that the entire matrix (with zero entries) would not even fit in the available memory. This is one motivation for a special type for sparse matrices. Another motivation is better performance of operations where zero matrix entries can be avoided.

There are only a very limited number of algorithms for general, unstructured sparse matrices in linear algebra. Most of them are iterative in nature and based on efficient implementations of matrix-vector multiplication for sparse matrices.

Examples for sparse matrices are diagonal or banded matrices. The simple pattern of these matrices allows straightforward storing strategies; the principal diagonal and the sub- and super...

Summary


The concept of views is one of the important topics you should have learned from this chapter. Missing this topic will give you a hard time when debugging your code. Boolean arrays occur at various places throughout this book. They are handy and compact tools for avoiding lengthy if constructions and loops when working with arrays. In nearly all large computational projects, sparse matrices become an issue. You saw how these are handled and which related methods are available.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Scientific Computing with Python 3
Published in: Dec 2016Publisher: PacktISBN-13: 9781786463517
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Authors (3)

author image
Claus Führer

Claus Führer is a professor of scientific computations at Lund University, Sweden. He has an extensive teaching record that includes intensive programming courses in numerical analysis and engineering mathematics across various levels in many different countries and teaching environments. Claus also develops numerical software in research collaboration with industry and received Lund University's Faculty of Engineering Best Teacher Award in 2016.
Read more about Claus Führer