<jupyter_start><jupyter_text>![nerw_zad6_stopka.jpg](attachment:nerw_zad6_stopka.jpg) Programming Language With Numerical Methods<NAME>, Msc     Class 07. Numerical computations in Python 1. [NumPy](numpy)    1. [Creating arrays](arrays)    2. [Predefining arrays](predefine)    3. [Indexing and slicing](index)    4. [Loading and saving the data](save)    5. [Speed comparison](speed)    6. [Shape modifications](shape) 2. [Exercises](exercises) **Whenever you learn a new feature, you should try it out in interactive mode and make errors on purpose to see what goes wrong and what types of errors you run into.**  Numpy Some learning materials: - NumPy documentation. Quickstart: https://numpy.org/devdocs/user/quickstart.html - NumPy documentation. Tutorial for beginners: https://numpy.org/devdocs/user/absolute_beginners.html - SciPy lectures: https://scipy-lectures.org/intro/numpy/index.html - Visual guide to NumPy: https://betterprogramming.pub/numpy-illustrated-the-visual-guide-to-numpy-3b1d4976de1d - NumPy for Matlab users: https://numpy.org/doc/stable/user/numpy-for-matlab-users.html<jupyter_code>import numpy as np
a = [1, 2, 4]
for element in a:
    print(element**2)<jupyter_output>1
4
16<jupyter_text>Creating arrays ![arrays.png](attachment:arrays.png)  1D array<jupyter_code>a = np.arange(0, 2, 0.25)    # arange([start,] stop[, step,], dtype=None), works like range
print(type(a), 'a= \n', a.view())
print('size  a = ', np.size(a))   # number of elements in a
print('shape a = ', np.shape(a))  # shape of of a
b = np.array([[1, 2, 3]])   # creating an array from a list
print(type(b), 'b= \n', b.view())
print('size  b = ', b.size)   # number of elements in a
print('shape b = ', b.shape)  # shape of a
print('number of dimensions of b = ', b.ndim) # number of dimensions in b
b = np.array([1, 2, 3]) 
print(type(b), 'b= \n', b.view())
print('size  b = ', b.size)   # number of elements in a
print('shape b = ', b.shape)  # shape of a
print('number of dimensions of b = ', b.ndim) # number of dimensions in b<jupyter_output><class 'numpy.ndarray'> b= 
 [1 2 3]
size  b =  3
shape b =  (3,)
number of dimensions of b =  1<jupyter_text>2D array<jupyter_code>c = np.array([[1, 2, 3], [4, 5, 6]], dtype=float)
print(type(c), 'c= \n', c.view())
print('size  c = ', np.size(c))   
print('shape c = ', np.shape(c))<jupyter_output><class 'numpy.ndarray'> c= 
 [[1. 2. 3.]
 [4. 5. 6.]]
size  c =  6
shape c =  (2, 3)<jupyter_text>3D array<jupyter_code>d = np.array([[(1, 2, 3), (4, 5, 6)], [(7, 8, 9), (10, 11, 12)]],dtype = float)
print(type(d), 'd= \n', d.view())
print('size  d = ', np.size(d))  
print('shape d = ', np.shape(d))<jupyter_output><class 'numpy.ndarray'> d= 
 [[[ 1.  2.  3.]
  [ 4.  5.  6.]]

 [[ 7.  8.  9.]
  [10. 11. 12.]]]
size  d =  12
shape d =  (2, 2, 3)<jupyter_text>Changing data type<jupyter_code>a = np.arange(5, dtype='int64') # initializing an array with a defined numeric type 
print(a, a.dtype)       

b = np.arange(5, dtype='float64') # initializing an array with a defined numeric type 
print(b, b.dtype)   
a = np.array([np.arange(4), np.arange(4), np.arange(4)])
print(a.dtype)
b = a.astype('float')           # saving a copy of a with as floats
print(type(b)) 
print(b.dtype)
print(b.view())

a[0, 0] = 3.5                   # saving a float to an array containing float will cause truncating float to int
print(a)
# rounding the results
a = np.linspace(0, 1, 8)
b = np.around(a)
print(b.dtype)  # b is still float, despite the rounding!
print(b)<jupyter_output><empty_output><jupyter_text>Predefining arrays<jupyter_code>lin_array = np.linspace(0, 5, 15)          # creating an array containing 15 equally spaced values in range 0-5
print(lin_array)
zeroes_array = np.zeros((2, 3, 8))               # creating an array filled with zeroes (2 rows, 3 columns)
print(zeroes_array)

np.zeros(3)
ones_array = np.ones((2,3), dtype=np.float32) # creating an array filled with ones (2 rows, 3 columns)
print(ones_array)
hundreds = np.full((2,3), 100)              # creating an array filled with 100 (2 rows, 3 columns)
print(hundreds)
identity = np.eye(2)                     # creating an identity matrix (2 rows, 2 columns)
print(identity)
diagonal = np.diag(np.array([1, 2, 3, 4])) # creating a diagonal array
print(diagonal)
empty_array = np.empty((2,3))               # creating an empty (almost zero values) array (2 rows, 3 columns)
print(empty_array)
random_array = np.random.random((2, 3))       # creating an array filled with random values (2 rows, 3 columns)
print(random_array)
# check out also np.random.rand, np.random.randn, np.random.seed
a = random_array[:, 1:2]
a[0, 0] = 0
random_array<jupyter_output><empty_output><jupyter_text>Indexing and slicing ![slice.png](attachment:slice.png)(Source: http://scipy-lectures.org/intro/numpy/array_object.htmlindexing-and-slicing)<jupyter_code>a = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ])
print(a.view())
print('shape :', np.shape(a))
print('Element with indices [0, 0]:', a[0, 0]) # wskazanie elementu

a = np.array([ [1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5] ])
print(a.view())
print('shape :', np.shape(a))
a[0:3, 1:]                                    # slicing an array
a = np.full((5, 6), 100) 
a[:, 0] = 13  # filling col 0 with the same value
a[: ,3] = -1  # filling col 3 with the same value
a[4, :] = 0  # filling row 4 with the same value
print(a)<jupyter_output><empty_output><jupyter_text>Fancy indexingArrays can be indexed with slices, but also with boolean arrays. This method is called **fancy indexing**. Fancy indexing creates **copies** not views.<jupyter_code>a = np.array([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]])
a
mask = (a < 3) 
print(mask)
a[mask]
a = np.array([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]])
a[a < 3]
# indexing with an integer list
a = np.arange(0, 100, 10)
b = a[[2, 3, 2, 4, 2]]
print(b) # note: [2, 3, 2, 4, 2] is a Python list

a[[2, 3, 2, 4, 2]] = -10
print(a)

c = np.dot(a.T, a)
b = a.T.dot(a)
b<jupyter_output>[20 30 20 40 20]
[  0  10 -10 -10 -10  50  60  70  80  90]<jupyter_text>Operations on arrays<jupyter_code># elementwise operations
a = np.arange(10)
a = np.reshape(a, (2, 5))
print(a)
b = 2 * a
c = a + a
d = np.sin(a)
print(d)
print(a*a)<jupyter_output>[[0 1 2 3 4]
 [5 6 7 8 9]]
[[ 0.          0.84147098  0.90929743  0.14112001 -0.7568025 ]
 [-0.95892427 -0.2794155   0.6569866   0.98935825  0.41211849]]
[[ 0  1  4  9 16]
 [25 36 49 64 81]]<jupyter_text>Reducing the arrays (aggregating functions)![axes.png](attachment:axes.png)(Source: http://scipy-lectures.org/intro/numpy/array_object.htmlindexing-and-slicing)<jupyter_code>a = np.arange(10)
a = a.reshape((2, 5))
print(a)

# sum of all elements in a
print(a.sum())
# sum in columns
print(a.sum(axis=0))
# sum in rows
print(a.sum(axis=1))<jupyter_output>[[0 1 2 3 4]
 [5 6 7 8 9]]
45
[ 5  7  9 11 13]
[10 35]<jupyter_text>Check out:    - `min` (and `argmin`)    - `max` (and `argmax`)    - `mean`    - `std`    - `meadian`    - `cumsum`  Loading and saving the dataNumPy enables saving and loading data from binary files (like `.mat` files in Matlab)<jupyter_code>a = np.full((2,3), 100) 
b = np.full((5,5),10) 
np.save('my_array', a)         # saves an array to harddrive in a binary format
np.savez('array.npz', a, b)    # saves an array to harddrive in a binary format
test = np.load('my_array.npy') # reads an array stored in a binary format
print(test)
a = np.full((7, 6), 10)
b1 = a.astype('int32') 
# saving to a text file: https://numpy.org/doc/stable/reference/generated/numpy.savetxt.html
np.savetxt("myarray.txt", b1, delimiter=',', fmt = '%10.2f', header = 'header content')

# reading: https://numpy.org/doc/stable/reference/generated/numpy.genfromtxt.html
c = np.genfromtxt("myarray.txt", delimiter=',', skip_header = 1 , usecols =(5, 4, 3, 1) )
print(c)<jupyter_output><empty_output><jupyter_text>Speed comparison of NumPy and list operations<jupyter_code>L = range(1000) # creating a list with 1000 elements
%timeit [i**2 for i in L]
a = np.arange(1000)
%timeit a**2<jupyter_output>1.04 µs ± 27.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)<jupyter_text>Shape modificationshttps://numpy.org/devdocs/reference/routines.array-manipulation.html<jupyter_code># flattening the array, ravel() or flatten() - one of them returns a copy and one returns a view
# check out which is which :)
a = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2 , 3, 4]])
a.ravel()
# reshaping: number of elements must remain the same
a = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2 , 3, 4]])
print('shape a: ', a.shape) # (3x4)
print(a.view())

b = np.reshape(a, (2,6)) # reshape(a, newshape, order='C') <- order: columns or rows
print('shape b: ', b.shape)
print(b.view())

c = np.reshape(a, (4,-1)) # -1 works as a filler for the remaining size
print('shape c: ', c.shape)
print(c)
# changing the size of the matrix (including the change in a number of elements)
a = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2 , 3, 4]])
print('shape a: ', a. shape) 
print(a.view())

b = np.resize(a, (2,3) )
print('shape b: ', b.shape)
print(b.view())
# adding a dimension
z = np.array([1, 2, 3])
print(z.ndim)
z = z[:, np.newaxis]
print(z.ndim)
#adding elements to the end of the matrix

a = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])

b = np.append(a, [9,9,9,9])
print(b.view())
# inserting new elements

a = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])

b = np.insert(a, 3, 5) # inserting an element at an index 3 with a value 5, requires assignment
print(b.view())
# removing the element

a = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])

b = np.delete(a, [0])  # removes the element with the index given in brackets
print(b.view())
# joining two arrays of the same size (one below the other)
a = np.array([[1,2,3,4], [1,2,3,4], [1,2,3,4]])
b = np.array([[9,9,9,9], [8,8,8,8], [8,8,8,8]])

np.concatenate((a,b))
# joining two arrays horizontally and vertically
a = np.array([ [1,2,3,4], [1,2,3,4], [1,2,3,4] ])
b = np.array([ [9,9,9,9], [8,8,8,8], [8,8,8,8] ])

vertical = np.vstack((a,b))
print(vertical.view())

horizontal = np.hstack((a,b))
print(horizontal.view())
# Separating arrays
a = np.array([ [1,2,3,4], [1,2,3,4], [1,2,3,4] ])
b = np.array([ [9,9,9,9], [8,8,8,8], [8,8,8,8] ])
vertical = np.vstack((a,b))
print(vertical.view())

vertical_split = np.vsplit(vertical, 2)
print(vertical_split)


# horizontal
a = np.array([ [1,2,3,4], [1,2,3,4], [1,2,3,4] ])
b = np.array([ [9,9,9,9], [8,8,8,8], [8,8,8,8] ])
horizontal = np.hstack((a,b))
print(horizontal.view())

horizontal_split = np.hsplit(horizontal, 2)
print(horizontal_split)<jupyter_output><empty_output><jupyter_text>Exercises **Exercise 0**Create an 8x8 table (called `A`) and fill it with values. You can use random numbers or any other assignment that provides different values in rows (with at least one value equal to 1). Create a table called `B` that contains a part of `A` -- a cross-section of 4 rows and 4 columns.  - assign a new value to B[1, 1]. Print table `A`. What happened? Why? What can you do to keep `A` intact? - Change all 1 in A to 3. **Exercise 1**Let `x = np.arange(12.0)`. Use `shape` and `reshape` to produce $1\times 12$, $2\times 6$, $3\times 4$, $4\times 3$, $6\times 2$ versions of the array. Then, return `x` to its original size. **Exercise 2**Let  `x = np.reshape(np.arange(12.0), (4, 3))`. Use `ravel`, `flat` and `flatten` to extract elements with indices: 0, 2, 4, $\ldots$ **Exercise 3**Use `hstack`, `vstack` and `tile` to construct a matrix `A`:    $$    \renewcommand{\arraystretch}{1.5} % give some more room    A =    \left[\begin{array}{@{}cc@{}}    x &    \begin{matrix}    y&y&y \\    y&y&y \\    \end{matrix}    \\     z&    \begin{matrix}    & z^T & \\    y&y&y    \end{matrix}    \end{array}\right]    $$ **Exercise 4**Given a vector $v = (2, 3, -1)$ and a function $f(X) = x^3 + xe^x +1$, apply $f$ to each element in $v$. Then calculate $f(v)$ using vector computing rules. Prove that the results are equal. **Exercise 5**Try out different methods to create an array. Next, create an array $w$ with values $0, 0.1, 0.2 \ldots, 3$. What are results of calls: `w[:]`, `w[:-3]`, `w[::4]`, `w[2:-1:6]`. **Exercise 6**Solve the linear equation system $\mathbf{Ax} = \mathbf{b}$: $$ \begin{matrix}2a &+  b  &+  c &= 4  \\a  &+  3b &+ 2c &= 5 \\a  &      &   &= 6 \end{matrix}$$$$A = \begin{bmatrix} 2 & 1 & 1 \\ 1 & 3 & 2 \\ 1 & 0 & 0\end{bmatrix}, \quad B = \begin{bmatrix} 4\\ 5 \\ 6 \end{bmatrix}, \quad x = \begin{bmatrix} a\\ b \\ c \end{bmatrix}$$Solve the equation using `ndarray`. Verify the result with one of the \texttt{numpy.linalg} functions. Hint: $$ x = A^{-1}B, $$ solution:  a =  6,  b = 15, c =-23 **Exercise 7**The table below contains an epoch (col 1), satellite vehicle number (col 2), the satellite azimuth (col 3) and elevation (col 4); azimuth and elevation are given in degrees. - Find all the rows in which elevation > azimuth; - Find all the rows with elevation < 15 degrees. Change those values to `None`; - Find all the information for satellite 7 and save them to a new array; - Divide the table into two parts, each of the new table should contain information for one epoch only;<jupyter_code>import numpy as np
A = np.array([
    [1, 5, 29.421, 5.625],
    [1, 7, -41.081, 25.076],
    [1, 13, 45.508, 23.458],
    [1, 15, 83.187, 18.285],
    [1, 16, -134.711, 47.712],
    [2, 5, 29.418, 5.613],
    [2, 7, -41.097, 25.074],
    [2, 18, 151.603, 37.246],
    [2, 19, -79.059, 24.115],
    [2, 21, 109.807, 59.826],
    [2, 22, 179.439, 12.419]])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.18169771037326068, 'fraction_numerical': 0.06662740189943311, 'mean_word_length': 3.784783374427615, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 54, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '467532', 'license': 'MIT', 'n_tokens_mistral': 5901, 'n_tokens_neox': 5306, 'n_words': 1672, 'path': 'class_09_numpy/LNM_class_07_numpy.ipynb', 'repo_name': 'Fikrahelhifzi/Python_Numerical_Method', 'size': '13595'}