This can be considered a continuation of __part 1__.

**Slicing of Numpy Arrays:**

Slicing in NumPy works similarly to slicing in Python’s built-in lists, but has some additional features that can be useful. The general syntax for slicing a NumPy array is a[start:stop:step, start:stop:step, ...], where a is the array you want to slice, and start, stop, and step are the slicing parameters that specify the starting and ending indices, as well as the step size for each dimension.

Let’s look at this example:

```
import numpy as np
# Create a rank-2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# Use slicing to extract a subarray with shape (2, 2), starting at index (1, 1)
# [[6 7]
# [10 11]]
b = a[1:3, 1:3]
```

In this example, we create a rank-2 array with shape (3, 4), and then use slicing to extract a subarray with shape (2, 2), starting at index (1, 1).

The above example shows slicing of a two dimensional array. Following example shows a 3-dimensional array being sliced:

```
import numpy as np
# Create a rank-3 array with shape (2, 3, 4)
# [[[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
#
# [[13 14 15 16]
# [17 18 19 20]
# [21 22 23 24]]]
a = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]])
# Use slicing to extract a subarray with shape (1, 2, 2), starting at index (1, 1, 1)
# [[[18 19]
# [22 23]]]
b = a[1, 1:3, 1:3]
```

In this example, we create a rank-3 array with shape (2, 3, 4), and then use slicing to extract a subarray with shape (1, 2, 2), starting at index (1, 1, 1).

**Arithmetic Operations on Numpy Arrays:**

The arithmetic operations on Numpy arrays are the backbone of modern data science and machine learning. They are performed element-wise, meaning that the operation is applied to each element in the arrays independently. For example, consider the following rank-2 array with shape (2, 3):

```
import numpy as np
# Create a rank-2 array with shape (2, 3)
# [[1 2 3]
# [4 5 6]]
a = np.array([[1, 2, 3], [4, 5, 6]])
```

If we perform an arithmetic operation on this array, such as addition, the operation is applied element-wise, resulting in a new array with the same shape:

```
# Add 3 to each element in the array
# [[4 5 6]
# [7 8 9]]
b = a + 3
```

Similarly, if we perform an operation between two NumPy arrays, the operation is applied element-wise, resulting in a new array with the same shape as the original arrays:

```
# Create another rank-2 array with shape (2, 3)
# [[7 8 9]
# [10 11 12]]
c = np.array([[7, 8, 9], [10, 11, 12]])
```

```
# Add the arrays element-wise
# [[ 8 10 12]
# [14 16 18]]d = a + c
```

NumPy also provides many useful functions for performing common mathematical operations on arrays, such as np.sum(), np.mean(), and np.max(). These functions can be used to perform aggregation operations on arrays, such as calculating the sum or mean of all the elements in an array.

When performing arithmetic operations on NumPy arrays with different shapes, the arrays must be broadcastable, meaning that their shapes are compatible in the following sense:

For each dimension, the size of the arrays must either be the same, or one of the arrays must have size 1.

If the arrays are not broadcastable, a ValueError will be raised. Here is an example of how broadcasting works:

```
import numpy as np
# Create a rank-2 array with shape (2, 3)
# [[1 2 3]
# [4 5 6]]
a = np.array([[1, 2, 3], [4, 5, 6]])
# Create a rank-1 array with shape (3,)
# [7 8 9]
b = np.array([7, 8, 9])
# Add the arrays
# [[ 8 10 12]
# [11 13 15]]
c = a + b
```

In this example, the rank-1 array b is broadcasted to the same shape as the rank-2 array a in order to perform the addition operation. The resulting array c has the same shape as a.

Here is another example of broadcasting:

```
import numpy as np
# Create a rank-2 array with shape (2, 3)
# [[1 2 3]
# [4 5 6]]
a = np.array([[1, 2, 3], [4, 5, 6]])
# Create a rank-1 array with shape (2,)
# [7 8]
b = np.array([7, 8])
# Add the arrays
# [[ 8 10 12]
# [11 13 15]]
c = a + b
```

The above exampled, the arrays are not broadcastable and this will raise an error.

This is the end of the soft intro to Numpy Arrays, keep practicing!

## Commenti