Skip to content

Commit

Permalink
Merge pull request #63 from Gitstar-OC/math-algebra
Browse files Browse the repository at this point in the history
Math algebra
  • Loading branch information
Gitstar-OC authored Oct 11, 2024
2 parents b8da95b + 55a0474 commit a999433
Show file tree
Hide file tree
Showing 6 changed files with 761 additions and 49 deletions.
5 changes: 5 additions & 0 deletions app/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,9 @@ img, video {
/***************** For UL lists styling in mdx **************/
.prose :where(ul):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
margin-left: 1rem;
}

/*********** gap between lines in code block ***************/
.fd-codeblock code {
row-gap: 5px;
}
4 changes: 2 additions & 2 deletions components/ui/Appearance/appearance.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ const Appearance = ({ className }) => {
// "--h5-size": "10px",
// data-radix-scroll-area-viewport
// "--h6-size": "8px",
"--code": "18px", //16px
"--code-block": "18px"
"--code": "17px", //16px
"--code-block": "17px"
// "--size": "16px",
/// overflow of the code component is hidden
},
Expand Down
258 changes: 257 additions & 1 deletion content/learn/algebra/introduction-to-numpy-arrays.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,260 @@ One of the advantages of using NumPy is that you can easily create arrays with b
- `np.ones()` - Returns a new array setting values to one.
- `np.zeros()` - Returns a new array setting values to zero.
- `np.empty()` - Returns a new uninitialized array.
- `np.random.rand()` - Returns a new array with values chosen at random.
- `np.random.rand()` - Returns a new array with values chosen at random.

```py
# Return a new array of shape 3, filled with ones.
ones_arr = np.ones(3)
print(ones_arr)
```

```py
# Return a new array of shape 3, filled with zeroes.
zeros_arr = np.zeros(3)
print(zeros_arr)
```

```py
# Return a new array of shape 3, without initializing entries.
empt_arr = np.empty(3)
print(empt_arr)
```

```py
# Return a new array of shape 3 with random numbers between 0 and 1.
rand_arr = np.random.rand(3)
print(rand_arr)
```
---

## Multidimensional Arrays

With NumPy you can also create arrays with more than one dimension. In the above examples, you dealt with 1-D arrays, where you can access their elements using a single index. A multidimensional array has more than one column. Think of a multidimensional array as an excel sheet where each row/column represents a dimension.

```py
# Create a 2 dimensional array (2-D)
two_dim_arr = np.array([[1,2,3], [4,5,6]])
print(two_dim_arr)
```

An alternative way to create a multidimensional array is by reshaping the initial 1-D array. Using `np.reshape()` you can rearrange elements of the previous array into a new shape.

```py
# 1-D array
one_dim_arr = np.array([1, 2, 3, 4, 5, 6])

# Multidimensional array using reshape()
multi_dim_arr = np.reshape(
one_dim_arr, # the array to be reshaped
(2,3) # dimensions of the new array
)
# Print the new 2-D array with two rows and three columns
print(multi_dim_arr)
```

## Finding size, shape and dimension.

In future assignments, you will need to know how to find the size, dimension and shape of an array. These are all atrributes of a `ndarray` and can be accessed as follows:
- `ndarray.ndim` - Stores the number dimensions of the array.
- `ndarray.shape` - Stores the shape of the array. Each number in the tuple denotes the lengths of each corresponding dimension.
- `ndarray.size` - Stores the number of elements in the array.

```py
# Dimension of the 2-D array multi_dim_arr
multi_dim_arr.ndim
```

```py
# Shape of the 2-D array multi_dim_arr
# Returns shape of 2 rows and 3 columns
multi_dim_arr.shape
```

```py
# Size of the array multi_dim_arr
# Returns total number of elements
multi_dim_arr.size
```

## Array math operations

In this section, you will see that NumPy allows you to quickly perform elementwise addition, substraction, multiplication and division for both 1-D and multidimensional arrays. The operations are performed using the math symbol for each '+', '-' and '*'. Recall that addition of Python lists works completely differently as it would append the lists, thus making a longer list. Meanwhile, trying to subtract or multipy Python lists simply would cause an error.

```py
arr_1 = np.array([2, 4, 6])
arr_2 = np.array([1, 3, 5])

# Adding two 1-D arrays
addition = arr_1 + arr_2
print(addition)

# Subtracting two 1-D arrays
subtraction = arr_1 - arr_2
print(subtraction)

# Multiplying two 1-D arrays elementwise
multiplication = arr_1 * arr_2
print(multiplication)
```

## Multiplying vector with a scalar (broadcasting)
Suppose you need to convert miles to kilometers. To do so, you can use the NumPy array functions that you've learned so far. You can do this by carrying out an operation between an array (miles) and a single number (the conversion rate which is a scalar). Since, 1 mile = 1.6 km, NumPy computes each multiplication within each cell.

This concept is called **broadcasting**, which allows you to perform operations specifically on arrays of different shapes.

```py
vector = np.array([1, 2])
vector * 1.6
```

## Indexing and slicing
Indexing is very useful as it allows you to select specific elements from an array. It also lets you select entire rows/columns or planes as you'll see in future assignments for multidimensional arrays.

## Indexing
Let us select specific elements from the arrays as given.

```py
# Select the third element of the array. Remember the counting starts from 0.
a = np.array([1, 2, 3, 4, 5])
print(a[2])

# Select the first element of the array.
print(a[0])
```

For multidimensional arrays of shape `n`, to index a specific element, you must input `n` indices, one for each dimension. There are two common ways to do this, either by using two sets of brackets, or by using a single bracket and separating each index by a comma. Both methods are shown here.

```py
# Indexing on a 2-D array
two_dim = np.array(([1, 2, 3],
[4, 5, 6],
[7, 8, 9]))

# Select element number 8 from the 2-D array using indices i, j and two sets of brackets
print(two_dim[2][1])

# Select element number 8 from the 2-D array, this time using i and j indexes in a single
# set of brackets, separated by a comma
print(two_dim[2,1])
```

## Slicing
Slicing gives you a sublist of elements that you specify from the array. The slice notation specifies a start and end value, and copies the list from start up to but not including the end (end-exclusive).

The syntax is:

`array[start:end:step]`

If no value is passed to start, it is assumed `start = 0`, if no value is passed to end, it is assumed that `end = length of array - 1` and if no value is passed to step, it is assumed `step = 1`.

Note you can use slice notation with multi-dimensional indexing, as in `a[0:2, :5]`. This is the extent of indexing you'll need for this course but feel free to check out [the official NumPy documentation](https://numpy.org/doc/stable/user/basics.indexing.html) for extensive documentation on more advanced NumPy array indexing techniques.

```py
# Slice the array a to get the array [2,3,4]
sliced_arr = a[1:4]
print(sliced_arr)
```

```py
# Slice the array a to get the array [1,2,3]
sliced_arr = a[:3]
print(sliced_arr)
```

```py
# Slice the array a to get the array [3,4,5]
sliced_arr = a[2:]
print(sliced_arr)
```

```py
# Slice the array a to get the array [1,3,5]
sliced_arr = a[::2]
print(sliced_arr)
```

```py
# Note that a == a[:] == a[::]
#print(a == a[:] == a[::])
```

```py
# Slice the two_dim array to get the first two rows
sliced_arr_1 = two_dim[0:2]
sliced_arr_1
```

```py
# Similarily, slice the two_dim array to get the last two rows
sliced_two_dim_rows = two_dim[1:3]
print(sliced_two_dim_rows)
```

```py
# This example uses slice notation to get every row, and then pulls the second column.
# Notice how this example combines slice notation with the use of multiple indexes
sliced_two_dim_cols = two_dim[:,1]
print(sliced_two_dim_cols)
```

## Stacking #
Finally, stacking is a feature of NumPy that leads to increased customization of arrays. It means to join two or more arrays, either horizontally or vertically, meaning that it is done along a new axis.

- `np.vstack()` - stacks vertically
- `np.hstack()` - stacks horizontally
- `np.hsplit()` - splits an array into several smaller arrays

```py
a1 = np.array([[1,1],
[2,2]])
a2 = np.array([[3,3],
[4,4]])
print(f'a1:\n{a1}')
print(f'a2:\n{a2}')
```

```py
# Stack the arrays vertically
vert_stack = np.vstack((a1, a2))
print(vert_stack)

```

```py
# Stack the arrays horizontally
horz_stack = np.hstack((a1, a2))
print(horz_stack)
```



```py
# Split the horizontally stacked array into 2 separate arrays of equal size
horz_split_two = np.hsplit(horz_stack,2)
print(horz_split_two)

# Split the horizontally stacked array into 4 separate arrays of equal size
horz_split_four = np.hsplit(horz_stack,4)
print(horz_split_four)

# Split the horizontally stacked array after the first column
horz_split_first = np.hsplit(horz_stack,[1])
print(horz_split_first)
```

```py
# Split the vertically stacked array into 2 separate arrays of equal size
vert_split_two = np.vsplit(vert_stack,2)
print(vert_split_two)

# Split the horizontally stacked array into 4 separate arrays of equal size
vert_split_four = np.vsplit(vert_stack,4)
print(vert_split_four)

# Split the horizontally stacked array after the first and third row
vert_split_first_third = np.vsplit(vert_stack,[1,3])
print(vert_split_first_third)
```

Congratulations on learning your first topic.
Loading

0 comments on commit a999433

Please sign in to comment.