## Why use NumPy Arrays?¶

NumPy arrays are a lot like Python lists, but

- arrays are
*faster*than lists (for*accessing*data) - lists can store mixed types (e.g. ints
*and*floats). The data in an array must be of the same type (e.g. ints*or*floats).*but not both*

Because arrays contain a homogeneous data type, you can do things like `sum()`

an array of floats without worry that one of those elements might be a string.

## Basic Array Operations¶

### Make a 1-d array¶

You can make a 1-d array from a list.

#### Print the array¶

#### Check its dimensionality¶

#### Check its shape¶

#### Check how many elements are in the array¶

### Make a 2-d array¶

You can make a 2-d array from a list of lists.

#### Check its dimensionality¶

#### Check its shape¶

#### Check its length¶

Tip

You might be surprised to see `arr_2d`

has length 2, not 10. That's because `arr_2d`

can be interpreted as an array that contains 2 arrays inside it. If you want to get the total number of nested elements in the array, you can use the array `size`

attribute.

#### Check how many elements are in the array¶

#### Check the object's type¶

#### Check what type of data the array contains¶

## Rules For Every NumPy Array¶

There are two basic rules for every numpy array..

- Every element in the array must be of the same type and size.
- If an array's elements are also arrays, those inner arrays must have the same type and number of elements as each other. In other words, multidimensional arrays must be rectangular, not jagged.

*Good:*

*Bad:*

Info

If you try to make an array from a list that contains a mix of integers and strings, numpy doesn't error. *But*, it casts the integers to strings in order to satisfy the property that every element is the same type.

*Bad:*

Info

If you try to make an array from jagged lists like this, numpy doesn't error but it creates an array of *objects*. This means the array is essentially a Python list and lacks the performance benefits of using an array.

## Creating NumPy Arrays¶

### How to make a 1-d array from a list¶

### How to make a 2-d array from a list of lists¶

### How to make a 3-d array from a list of lists of lists¶

Info

You can make follow this pattern to create higher dimensional arrays.

### How to make an array of zeros¶

A quick google search will lead you to the numpy documentation for `numpy.zeros`

.

#### Make a (3,) array of 0s¶

#### Make a (3,5) array of 0s¶

### How to make an array filled with *any* value¶

See `numpy.full`

.

### How to make a sequence array 1, 2, ... N¶

Note

Note that `start`

is *inclusive* while `stop`

is *exclusive*.

*Alternatively:*

## Indexing 1-D Arrays¶

Start by making a 1d array called `foo`

with five elements.

### Access the ith element of an array¶

We can access the ith element just like a python list using square bracket notation where the first element starts at index zero.

### Modify the ith element¶

*Set the 2nd element to 99*

### Access the last element¶

### Negative Indexing¶

Just like python lists, we can use negative indexing..

### Out of bounds error¶

If we try to access an element outside the bounds of the array, we’ll get an “out of bounds” error.

- IndexError: index 999 is out of bounds for axis 0 with size 5

### Accessing multiple elements¶

We can access multiple elements using a list or numpy array of indices.

*Example*

*Indices can be repeated..*

*Indices can be another numpy array*

#### Array Slicing¶

We can use slicing just like python lists. The signature is essentially

Note

Note that `start index`

is *inclusive* while `end index`

is *exclusive*.

*Get every element from the beginning of the array to index 2 exclusive*

*Get every element from index 2 inclusive to the end of the array*

*Get every other element from the beginning of the array to the end*

### Modifying multiple elements¶

If you want to modify multiple elements of a 1-d array, you can use a list of indices and a list of assignment values. The list of assignment values should be the same length as the list of indices.

..or you can assign everything to a scalar.

## Indexing Multidimensional Arrays¶

Start by making a new `(3,4)`

array called `bar`

from a list of lists.

Internally, `bar`

is just a contiguous block of memory storing some data. Since we defined `bar`

using a list of lists,
numpy makes it a two-dimensional array, giving it **two axes** for indexing its values.

Since `bar`

has two axes (dimensions), numpy knows to interpret the data as a rectangular array where axis 0 is the row
axis and axis 1 is the column axis. This means we can subset `bar`

using a combination of *row* indices and *column*
indices.

### Get element in the 2nd row, third column¶

### Get first row as a 1-d array¶

### Get first row as a 2-d array¶

We’ll learn more about the None keyword later. Alternatively, you can use slicing for the row index.

### Get rows 2 & 3 with the 2nd-to-last and last columns¶

### Modifying multiple elements¶

*Replace the top left element of bar with -1*

*Replace the second row with the third row*

*Insert zeros on diagonal*

Notice here that the ith row index and the ith column index combine to **select a specific array element**. For
example, row index 1 combines with column index 1 to select element `bar[[1,1]]`

of bar.

## Interpreting Multidimensional Arrays¶

It's natural to interpret a three-dimensional array as a rectangular prism like this.

Unfortunately, this spacial model breaks down when you go *above* three dimensions. A better mental model is to interpret a 1-dimensional array as a row of numbers

a two-dimensional array as a matrix (rows and columns)

a three-dimensional array as a row of matrices

a four-dimensional array as a matrix of matrices

and so on. Now if you have a three-dimensional array like this

and you make an assignment like `zoo[0,:,1] = 5`

, you can interpret the assignment as

set the 1st matrix, every row, 2nd column equal to 5

Info

We've glossed over some gritty details and complex scenarios regarding array indexing which we'll cover later.

## Basic Math on Arrays¶

Start by defining a pair of 2x2 arrays, `foo`

and `bar`

.

### Addition¶

See what happens when we add `foo + bar`

The values of foo and bar get added *element-wise*. This pattern of element-wise addition holds true for every math
operation between identically sized arrays.

### Subtraction¶

### Multiplication¶

### Division¶

### Matrix Multiplication¶

Use the `@`

operator to do *matrix multiplication* between numpy arrays.

### Broadcasting Arithmetic¶

If you do `foo + 5`

, numpy adds 5 to *each* element of `foo`

.

The same goes for subtraction multiplication, division, and all other binary arithmetic operations. This behavior is
known as *broadcasting*. We'll discuss broadcasting in
detail later.