# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Numpy experiments

# Import numpy package.

import numpy as np

# ## Reshaping

# Optionally, the last index given in `reshape` can be `-1`, the shape will be such that the dimensions multiply to the size of the original array.

a = np.arange(1, 21, dtype=np.int).reshape(4, -1)
a

# In three dimensions, the last dimension can be replaced by `-1`.

b = a.reshape(2, 5, -1)
b

# ## Slicing

# Define 3D data with a "width" of 5, a "height" of 4, and a "depth" of 3.

a = np.arange(1, 61, dtype=np.int).reshape((3, 4, -1))

# When the last dimension is -1, it is computed automatically if possible, i.e., if the product of the sizes in each dimension is the size of the array.

a.shape

# When data is viewed as 3D, slice the "front" layer.

a[0, :, :]

# Slice the middle layer.

a[1, :, :]

# Slice the back layer.

a[2, :, :]

# Slice the top layer (first row is front).

a[:, 0, :]

# Slice the left layer (first row is front).

a[:, :, 0]

# Introducing new leading dimension.

a[None].shape

# Check that this is the original matrix, with size of leading dimension equal to 1.

np.all(a == a[None][0])

# Add additional "last" dimension, check that the result is the top-front row, with each element in an individual dimension 1 subarray.

a[:, :, :, None][0, 0]

# It is important to realize that slicing doesn't copy, i.e., a slice yields a reference to the original data. Consider the following matrix.

b = np.arange(1, 21).reshape(4, 5)
b

c = b[1:-1, 1:-1]
c

# Now we modify an element of `c`

c[0, 0] = 0
c

# Clearly, `c` was changed, but so is `b`.

b

# ## Fancy indexing

# Create a new $4 \times 5$ array.

a = np.arange(1, 21, dtype=np.int).reshape((4, -1))
a

# Select the second and fourth row.

a[[1, 3], :]

# Select the first and fourth column.

a[:, [0, 3]]

# ## Structured arrays

# Although strictly speaking not fancy indexing, we can create structured arrays, which you can think of as arrrays of structures. These arrays can be indexed by number, and by structure field name.

b = np.zeros(10, dtype={'names': ('x', 'y'), 'formats': ('f8', 'f8')})
b

# Each element acts as a tuple, the first field has name `x` and type `np.float`, the second has name `y`, and is also `np.float`.

# The shape shows it is an 1-D array.

b.shape

# The type of the elements is perhaps a bit surprising.

type(b[0])

# We can initialize the `x` and `y` fields of each array element with a single assingment.

b['x'] = np.random.uniform(size=10)
b['y'] = np.random.uniform(size=10)
b

b['x']

# Using a numerical index gives the corresponding element in the array.

b[0]

# Accessing elements by field number or field name is equivalent.

b[4][1] == b[4]['y']

# ## Stacking

# Create two matrices, both $4 \times 5$.

a = np.arange(1, 21, dtype=np.int).reshape((4, -1))
b = np.arange(21, 41, dtype=np.int).reshape((4, -1))
print(a)
print(b)

# Stack matrices horizontally.

np.hstack((a, b))

# Stack matrices vertically.

np.vstack((a, b))

# Create a list of 3 arrays, each $4 \times 5$.

arrays_2d = []
size_2d = 20
for i in range(3):
    upperleft = i*size_2d + 1
    arrays_2d.append(np.arange(upperleft, upperleft + size_2d, dtype=np.int).reshape(4, -1))

# Create a 3D array out of the list of 2D arrays.

# +
array_3d = np.array(arrays_2d)

array_3d.shape
# -

# Get front plane.

array_3d[0, :, :]

# Get top plane.

array_3d[:, 0, :]



StarcoderdataJupyterScriptsDedupFiltered