```python
# Double resolution figures for MacOSX retina displays
%config InlineBackend.figure_format = 'retina'
```

# NumPy
* Makes working with N-dimensional arrays (e.g. vectors, matrices, tensors) effecient.
* NumPy functions are written in C, so they're fast. In fact, Python itself is written in C.


```python
import numpy as np  # import numpy module
```

## N-dimensional arrays


```python
a = np.array([1, 2, 3, 4, 5])
print(a)
print()
print("a.shape = ", a.shape)
print("type(a) = ", type(a))
print("a.dtype = ", a.dtype)
```

    [1 2 3 4 5]
    
    arr.shape =  (5,)
    type(arr) =  <class 'numpy.ndarray'>
    arr.dtype =  int64



```python
a = np.zeros((3, 3))  # 3x3 random matrix
print(a)
print()
print("a.shape = ", a.shape)
print("type(a) = ", type(a))
print("a.dtype = ", a.dtype)
```

    [[0. 0. 0.]
     [0. 0. 0.]
     [0. 0. 0.]]
    
    arr.shape =  (3, 3)
    type(arr) =  <class 'numpy.ndarray'>
    arr.dtype =  float64



```python
a = np.zeros((3, 3), dtype=int)  # 3x3 random matrix
print(a)
print()
print("a.shape = ", a.shape)
print("type(a) = ", type(a))
print("a.dtype = ", a.dtype)
```

    [[0 0 0]
     [0 0 0]
     [0 0 0]]
    
    arr.shape =  (3, 3)
    type(arr) =  <class 'numpy.ndarray'>
    arr.dtype =  int64



```python
a = np.random.rand(2, 3, 3)  # 3x3 random matrix of floats in [0, 1)
print(a)
print()
print("a.shape = ", a.shape)
print("type(a) = ", type(a))
print("a.dtype = ", a.dtype)
```

    [[[0.03111165 0.97138943 0.19205285]
      [0.42724477 0.02948653 0.46096785]
      [0.00898452 0.99232939 0.7564268 ]]
    
     [[0.81428869 0.52431353 0.04443435]
      [0.53670176 0.86850834 0.31947024]
      [0.56926624 0.45408431 0.73173848]]]
    
    arr.shape =  (2, 3, 3)
    type(arr) =  <class 'numpy.ndarray'>
    arr.dtype =  float64



```python
def show_array_info(a):
    print(arr)
    print()
    print("arr.shape = ", arr.shape)
    print("type(arr) = ", type(arr))
    print("arr.dtype = ", arr.dtype)
```


```python
a = np.random.randint(1, 10, size=(5, 5))  # 3x3 random matrix of ints between 1 and 10
show_array_info(a)
```

    [[8 6 7]
     [4 5 5]
     [7 9 4]]
    
    arr.shape =  (3, 3)
    type(arr) =  <class 'numpy.ndarray'>
    arr.dtype =  int64


## Array indexing


```python
m = np.random.randint(1, 10, size=(5, 5))  # 3x3 random matrix of ints between 1 and 10
print(m)

m[0,0], m[1,0], m[3,4]  # [row,col] indexes
```

    [[4 9 7 2 9]
     [8 2 4 3 6]
     [8 3 8 6 7]
     [7 6 3 6 2]
     [6 4 2 7 7]]





    (4, 8, 2)




```python
m[4,4] = 100
m
```




    array([[  4,   4,   5,   7,   4],
           [  9,   7,   9,   6,   6],
           [  1,   6,   9,   4,   5],
           [  1,   1,   1,   6,   2],
           [  1,   9,   9,   7, 100]])



## Subarrays


```python
m[0,:]  # 1st row
```




    array([5, 5, 1, 4, 6])




```python
m[:,3]  # 4th col
```




    array([4, 2, 9, 1, 4])




```python
m[1:3,3]  # 2nd-3rd elements in 4th col
```




    array([2, 9])






## Reductions


```python
m = np.random.randint(1, 10, size=(5, 5))  # 3x3 random matrix of ints between 1 and 10
print(m)
m.min(), m.max(), m.mean(), m.var(), m.std()  # min, max, mean, variance, standard deviation
```

    [[9 8 2 3 8]
     [8 4 7 4 7]
     [3 7 2 3 8]
     [3 4 5 5 4]
     [1 7 6 8 4]]





    (1, 9, 5.2, 5.28, 2.2978250586152114)



## Partial reductions


```python
m.max(axis=0), m.max(axis=1)  # max across rows (axis=0) and cols (axis=1), respectively
```




    (array([9, 8, 7, 8, 8]), array([9, 8, 8, 5, 8]))



## Array multiplication


```python
A = np.random.randint(1, 10, size=(2, 2))  # 2x2 random matrix of ints between 1 and 10
b = np.array([2, 3])  # length 2 row vector
c = np.reshape(b, (2, 1))  # b as a col vector instead of row vector
print(A)
print()
print(b)
print()
print(c)
```

    [[9 7]
     [7 8]]
    
    [2 3]
    
    [[2]
     [3]]


### Element-wise multiplication


```python
print(A)
print()
print(A * A)
```

    [[9 7]
     [7 8]]
    
    [[81 49]
     [49 64]]



```python
print(b)
print()
print(b / 2)
```

    [2 3]
    
    [1.  1.5]


### Broadcasting


```python
print(A)
print()
print(b)
print()

print(A * b)  # element-wise multiplication of b with each row of A
```

    [[6 5]
     [6 7]]
    
    [2 3]
    
    [[12 15]
     [12 21]]



```python
print(b)
print()
print(c)
```

    [2 3]
    
    [[2]
     [3]]



```python
print(A)
print()
print(c)
print()

print(A * c)  # element-wise multiplication of c with each col of A
```

    [[5 2]
     [8 8]]
    
    [[2]
     [3]]
    
    [[10  4]
     [24 24]]




## Matrix multiplication

\begin{equation}\label{eq:matrixeqn}
     \begin{pmatrix}
       m_{00} & m_{01} & m_{02} \\
       m_{10} & m_{11} & m_{12} \\
       m_{20} & m_{21} & m_{22}
     \end{pmatrix}
     \cdot
     \begin{pmatrix}
       v_{0} \\
       v_{1} \\
       v_{2}
     \end{pmatrix}
     =
     \begin{pmatrix}
       m_{00} * v_{0} + m_{01} * v_{1} + m_{02} * v_{2} \\
       m_{10} * v_{0} + m_{11} * v_{1} + m_{12} * v_{2} \\
       m_{20} * v_{0} + m_{21} * v_{1} + m_{22} * v_{2}
     \end{pmatrix}
\end{equation}

(3 x 3) . (3 x 1) = (3 x 1)


```python
print(b)
print()
print(c)
print()
print(b.dot(c))
```

    [2 3]
    
    [[2]
     [3]]
    
    [13]



```python
c.dot(b)
```


```python
print(A)
print()
print(b)
print()
print(A.dot(b))
```

    [[6 5]
     [6 7]]
    
    [2 3]
    
    [27 33]



```python
print(A)
print()
print(c)
print()
print(A.dot(c))
```

    [[6 5]
     [6 7]]
    
    [[2]
     [3]]
    
    [[27]
     [33]]


## Speed and timing
* Basically do everything in numpy that you possibly can because it's *much much* faster than native python code.


```python
import timeit
import time

start = timeit.default_timer()  # timestamp in sec
time.sleep(2)  # sleep 2 sec
stop = timeit.default_timer()  # timestamp in sec

stop - start  # elapsed time
```




    2.000289000999601




```python
a = np.linspace(1, 1000000, num=1000000, endpoint=True)  # 1-1000000
start = timeit.default_timer()
for i in range(len(a)):
    a[i] = a[i]**2
stop = timeit.default_timer()
stop - start
```




    0.418272782999793




```python
a = np.linspace(1, 1000000, num=1000000, endpoint=True)  # 1-1000000
start = timeit.default_timer()
a = a**2
stop = timeit.default_timer()
stop - start
```




    0.002637679000144999



# Plot with matplotlib
Many more types of plots than those shown below can be made, such as histograms, contours, etc. Lot's of info on these is available online.


```python
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d  # for 3d plots
```


```python
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100)

fig = plt.figure()  # make a figure
plt.plot(x, y, 'o')  # plot x vs. y in current figure using circle markers
plt.plot(x, z, 'o')  # plot x vs. y in current figure using circle markers
plt.xlabel('x')
plt.ylabel('y or z')
plt.title('2d plot')
plt.legend(['x', 'y']);  # last semicolon suppresses title object output
```


```python
fig = plt.figure()  # make a figure
ax = plt.axes(projection='3d')  # set axes of current figure to 3d axes (this requires having imported mplot3d from mpl_toolkits)
ax.scatter(x, y, z)  # 3d scatter plot of x vs. y vs. z
ax.scatter(x, z, y)  # 3d scatter plot of x vs. z vs. y
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.title('3d plot')
plt.legend(['x', 'y']);
```

## Subplots


```python
fig, ax = plt.subplots(nrows=2, ncols=3)

ax[0,0].scatter(x, y)
ax[0,0].set_xlabel('x')
ax[0,0].set_ylabel('y');

ax[1,1].scatter(x, z, marker='s', color='r')
ax[1,1].set_xlabel('x')
ax[1,1].set_ylabel('z')

ax[0,2].plot(range(len(y)), y, linestyle='-', color='c')
ax[0,2].set_ylabel('y')

fig.tight_layout();  # helps improve margins between plots
```

## Interactive plots
You may need to install the following for interactive plots in JupyterLab:

    > conda install -c conda-forge ipympl
    > conda install -c conda-forge widgetsnbextension
    > conda install nodejs
    > jupyter labextension install @jupyter-widgets/jupyterlab-manager
    > jupyter labextension install jupyter-matplotlib

`%matplotlib widget` will start using interactive plots

`%matplotlib inline` will go back to using non-interactive plots


```python
# interactive plot mode
%matplotlib widget

fig1 = plt.figure()  # make a figure
plt.plot(x, y, 'o')  # plot x vs. y in current figure using circle markers

fig2 = plt.figure()  # make a figure
ax = plt.axes(projection='3d')  # set axes of current figure to 3d axes
ax.scatter(x, y, z);  # 3d scatter plot of x vs. y vs. z
```


    FigureCanvasNbAgg()



    FigureCanvasNbAgg()



```python
# back to non-interactive plot mode
%matplotlib inline
```


```python

```

86a42b2c88c8af361f52c60de356c7ff7edbf704
ipynb
Jupyter Notebook
lecture_01_intro/numpy_basics.ipynb
marcofuentes064/NEU
03e2fd9de69c6985dea3279bfa5fca77f93d14b9
MIT
2019-06-14T01:46:33.000Z
2020-12-10T20:13:21.000Z
lecture_01_intro/numpy_basics.ipynb
marcofuentes064/NEU
03e2fd9de69c6985dea3279bfa5fca77f93d14b9
MIT
lecture_01_intro/numpy_basics.ipynb
marcofuentes064/NEU
03e2fd9de69c6985dea3279bfa5fca77f93d14b9
MIT
2019-01-24T20:24:53.000Z
2020-12-10T23:44:58.000Z
Qwen/Qwen-72B
1. YES
2. YES