---
jupyter:
  jupytext:
    text_representation:
      extension: .Rmd
      format_name: rmarkdown
      format_version: '1.0'
      jupytext_version: 0.8.1
  kernelspec:
    display_name: Python 3
    language: python
    name: python3
  language_info:
    codemirror_mode:
      name: ipython
      version: 3
    file_extension: .py
    mimetype: text/x-python
    name: python
    nbconvert_exporter: python
    pygments_lexer: ipython3
    version: 3.6.5
---

# Indexing with Boolean arrays

As usual with arrays, we need the Numpy library:

```{python}
import numpy as np
```

Just for neatness below, we will only show numbers in arrays to 2 decimal
places.  This doesn't affect any calculations, it just changes what we see when
we show arrays in Jupyter:

```{python}
# Set how many decimal places to display when showing arrays.
np.set_printoptions(precision=2)
```

## Select values with Boolean arrays

Here we are using Boolean arrays to *index* into other arrays.  You will see
what we mean by that by the end of this section.

We often want to select several elements from an array according to some
criterion.

The most common way to do this, is to do array slicing, using
a Boolean array between the square brackets.

It can be easier to understand this by example than by description.


We start with the [RateMyProfessors dataset](data/rate_my_professors).

It is a table where the rows are academic disciplines, and the columns contain
the average student rating values for the corresponding discipline.  We are
going to fetch the columns from this table as arrays.

If you are running on your laptop, you should download the
{download}`rate_my_course.csv <data/rate_my_course.csv>` file to the same
directory as this notebook.

```{python}
# We have not covered this code yet.  We will soon.
# Load the library for reading data files.
import pandas as pd
pd.set_option('mode.copy_on_write', True)
# Read the file into a table, select the first six rows.
big_courses = pd.read_csv('data/rate_my_course.csv').head(6)
# Put the columns into arrays, each with six elements.
# The disciplines (names of disciplines).
disciplines = np.array(big_courses['Discipline'])
# The corresponding average scores for Easiness.
easiness = np.array(big_courses['Easiness'])
```

We now have the names of the disciplines with the largest number of professors.

```{python}
disciplines
```

Here are the "Easiness" scores for the six largest courses:

```{python}
easiness
```

These are the easiness ratings corresponding to the `disciplines` we saw
earlier.  The top (largest) discipline is:

```{python}
disciplines[0]
```

The Easiness rating for that course is:

```{python}
easiness[0]
```

## Boolean arrays

Boolean arrays are arrays that contain values that are one of True or False.

Here is a Boolean array, created from applying a comparison to an array:

```{python}
greater_than_3 = easiness > 3
greater_than_3
```

This has a `True` value at the positions of elements > 3, and `False`
otherwise.


We can do things like count the number of `True` values in the Boolean array:

```{python}
np.count_nonzero(greater_than_3)
```

Now let us say that we wanted to get the elements from `easiness`
that are greater than 3.   That is, we want to get the elements in `easiness`
for which the corresponding element in `greater_than_3` is `True`.

We can do this with *Boolean array indexing*.  The Boolean array goes between
the square brackets, after the array name.  As a reminder:

```{python}
# The easiness array
easiness
```

```{python}
# The greater_than_3 Boolean array
greater_than_3
```

We put the Boolean array between square brackets, after the array we want to get values from, like this:

```{python}
# Boolean indexing into the easiness array.
easiness[greater_than_3]
```

We have selected the numbers in `easiness` that are greater than 3.

See the picture below for an illustration of what is happening:

![](images/easiness_values.png)

We can use this same Boolean array to index into another array.  For example,
here we show the discipline *names* corresponding to the courses with Easiness
scores greater than 3:

```{python}
disciplines[greater_than_3]
```

See the picture below for an illustration of how this works:

![](images/easiness_reused.png)


## Setting values with Boolean arrays

You have seen, above, that Boolean indexing can select values from an array:

```{python}
# Create the Boolean array
another_array = np.array([2, 3, 4, 2, 1, 5, 1, 0, 3])
are_gt_2 = another_array > 2
are_gt_2
```

```{python}
# Get the values by indexing with the Boolean array.
# Return only the values of 'another_array' where the Boolean array has True.
another_array[are_gt_2]
```

Given what you know, what do you think would happen with:

```
another_array[are_gt_2] = 10
another_array
```

Try it.
