mirror of
https://github.com/janishutz/eth-summaries.git
synced 2026-01-13 21:08:28 +00:00
[NumCS] Add numpy, scipy and sympy quick overview
This commit is contained in:
75
semester3/numcs/parts/06_python/00_intro.tex
Normal file
75
semester3/numcs/parts/06_python/00_intro.tex
Normal file
@@ -0,0 +1,75 @@
|
||||
Python is a high-level dynamically and strongly typed, multi-paradigm, interpreted programming language.
|
||||
Its syntax might remind you of pseudocode, which allows very quick writing, but lacks some control that other lower level programming languages might offer.
|
||||
Be aware that Python likes to call things differently (\texttt{try ... except} for example instead of \texttt{try ... catch} or \texttt{True, False} instead of \texttt{true, false}).
|
||||
|
||||
\subsection{Basics}
|
||||
\subsubsection{Variables}
|
||||
While Python supports many different paradigms (thus making it multi-paradigm), Python still is first and foremost an object oriented programming language and all variables
|
||||
are just references to objects.
|
||||
|
||||
What this means is that the variables aren't \textit{technically} conventional variables, but rather pointers and whenever you reassign a value,
|
||||
the object is actually deleted and a new object is created in its place and the variable's reference is updated. This is one of the reasons as to why
|
||||
Python is so slow.
|
||||
|
||||
Assigning and initializing variables uses the same syntax and you cannot have unassigned variables:
|
||||
\begin{code}{python}
|
||||
x # This will not work
|
||||
x = 1 # Notice that there is no type annotated (Python is dynamically typed)
|
||||
x = 10 # Assign another value to x
|
||||
x = "Hello World" # TypeError (Python is strongly typed)
|
||||
arr = [] # Creates an empty list. They are dynamically sized
|
||||
d = {} # Creates an empty dict (Dictionary)
|
||||
arr_list = [ "Hello", "World", 1 ] # Can contain multiple different elements
|
||||
\end{code}
|
||||
Python supports the same data types as most other programming languages,
|
||||
but gives some of them funny names (\texttt{bool}, \texttt{int}, \texttt{float}, \texttt{str}, \texttt{List}, \texttt{Dict} (\texttt{Map} in Java),
|
||||
\texttt{None} (\texttt{void} in basically all other languages))
|
||||
|
||||
To cast a type in python, the basic types are callable, i.e. to cast an \texttt{int} to a \texttt{str}, do \texttt{str(my\_int)}
|
||||
|
||||
|
||||
\subsubsection{Operations}
|
||||
Python uses the normal operators for basic arithmetic operations, however be aware that Python implicitly casts \texttt{int} to \texttt{float} when dividing.
|
||||
To do integer division use the \texttt{a // b} syntax. For exponentiation, Python supports the \texttt{a ** b} syntax (which computes $a^b$).
|
||||
Increment and decrement operators are not supported, however \texttt{+=}, etc are supported.
|
||||
|
||||
|
||||
|
||||
\subsubsection{Control flow}
|
||||
Python uses indents (that are consistent, i.e. always use \texttt{n} spaces or a tab character) to indicate blocks.
|
||||
You cannot use curly braces. In other ways though, Python is fairly lenient, i.e. you are allowed to write parenthesis around the if statement's condition
|
||||
|
||||
\begin{code}{python}
|
||||
# Can also use range(start, stop, step) for a traditional for-loop.
|
||||
# Parameters start and step can be both (or just one of them) omitted.
|
||||
for i in iterable:
|
||||
print(i)
|
||||
|
||||
for i, val in enumerate(iterable): # Get index and value (or key and value)
|
||||
print(i, val)
|
||||
|
||||
while True:
|
||||
break # Break statement to exit loop
|
||||
|
||||
if x > 1: # All blocks start with :
|
||||
print(1)
|
||||
elif x > 0:
|
||||
print(2)
|
||||
else:
|
||||
print(3)
|
||||
\end{code}
|
||||
|
||||
\subsubsection{Imports}
|
||||
Python has multiple ways of importing other libraries and from your own files.
|
||||
Your own imports are always relative to the run file (i.e. not to the current file, but the root file of either the library or your program).
|
||||
\begin{code}{python}
|
||||
import lib.mylib # Local import from file lib/mylib.py
|
||||
import numpy # Import numpy. Access numpy functions using numpy.<method>(...)
|
||||
import numpy as np # Alias numpy to np. Access using np.<method>(...)
|
||||
from numpy import array # Only import array method from numpy. Call using array(...)
|
||||
# The below is the biggest Python sin. DO NOT DO THIS!
|
||||
from numpy import * # Wildcard import (import all functions from the library as <method>(...))
|
||||
\end{code}
|
||||
What you should always refrain from doing is a wildcard import. Every function from that library is then imported directly and can be called using \texttt{<method>(...)}.
|
||||
Thus, if two libraries have a function that has the same name, your program will stop working, thus always either import a specific function, or better still,
|
||||
use the options on line 2 or 3 for library imports, as it is also much easier for other people to understand where the function is defined.
|
||||
103
semester3/numcs/parts/06_python/01_numpy.tex
Normal file
103
semester3/numcs/parts/06_python/01_numpy.tex
Normal file
@@ -0,0 +1,103 @@
|
||||
\newpage
|
||||
\subsection{Numpy}
|
||||
Numpy is a library that, according to its website, is ``The fundamental package for scientific computing with Python''.
|
||||
|
||||
If you prefer to read an online guide, the \hlhref{https://numpy.org/doc/stable/user/quickstart.html}{official quick start guide}\ is excellent.
|
||||
|
||||
\subsubsection{Arrays}
|
||||
The heart of numpy is the \texttt{numpy.ndarray} class (it has the alias \texttt{numpy.array}). As the name would imply, it can be any dimension you would like.
|
||||
The most important attributes for this course are: \texttt{shape} (returns a tuple that indicates the number of elements for each dimension),
|
||||
\texttt{dtype} (indicates the data type of elements in the array),
|
||||
\texttt{ndim} (the number of dimensions, equal to \texttt{len(shape)})
|
||||
|
||||
To create an array, we can use a few functions:
|
||||
\drmvspace
|
||||
\begin{multicols}{2}
|
||||
\begin{itemize}[noitemsep]
|
||||
\item \texttt{np.array([...])}
|
||||
\item \texttt{np.zeros(shape)}
|
||||
\item \texttt{np.zeros\_like(arr)}
|
||||
\item \texttt{np.ones(shape)}
|
||||
\item \texttt{np.ones\_like(arr)}
|
||||
\item \texttt{np.empty\_like(arr)}
|
||||
\item \texttt{np.arange(start, stop, step)}
|
||||
\item \texttt{np.linspace(start, stop, num\_el)}
|
||||
\item \texttt{np.logspace(start, stop, num\_el)}
|
||||
\item \texttt{np.eye(N, M)} (\texttt{N} is rows, \texttt{M} is cols)
|
||||
\item \texttt{np.identity(N, M)}
|
||||
\item \texttt{np.fromfunction(f, (dim1, \dots))}
|
||||
\end{itemize}
|
||||
\end{multicols}
|
||||
|
||||
\dnrmvspace
|
||||
To use complex numbers, we can write \texttt{a + b * 1.j}
|
||||
|
||||
Another useful method is \texttt{np.meshgrid(x, y, \dots)}, which returns a coordinate grid
|
||||
and treats the input vectors as \texttt{x}, \texttt{y}, etc coordinates of point \texttt{i}.
|
||||
|
||||
Arrays aren't usually copied, but you get a view. The \texttt{reshape} method below is an example of a case where you get a shallow copy (that still technically is a view).
|
||||
The values are still in the same object, but you get access to it in a different shape.
|
||||
To deep copy an array (i.e. create a new array), use \texttt{arr.copy()}
|
||||
|
||||
|
||||
\subsubsection{Operations}
|
||||
The same basic operations that Python supports are also supported by numpy, though they are executed on each element.
|
||||
|
||||
\begin{itemize}[noitemsep]
|
||||
\item You can subtract a number from an ndarray
|
||||
\item You can subtract an ndarray from another ndarray (vector, matrix, ... difference)
|
||||
\item To compute a matrix product (or matrix-vector product), you can do \texttt{A @ B} or \texttt{np.dot(A, B)}
|
||||
\item \texttt{arr.sum()} sums up all elements and \texttt{arr.sum(axis=n)} sums up all elements on that axis (0 is column, 1 is row)
|
||||
\item \texttt{arr.cumsum()} computes the cumulative sum (i.e. each element in the output is the sum of all preceding elements). You can also use the axis argument again.
|
||||
\item \texttt{np.exp}, \texttt{np.sqrt}, etc operate element-wise on the array
|
||||
\item \texttt{np.where(condition, arr\_true, arr\_false)} returns a numpy array where if \texttt{condition} is true,
|
||||
element \texttt{i} is chosen from \texttt{arr\_true}, else from \texttt{arr\_false}
|
||||
\end{itemize}
|
||||
A useful trick to create a mask is to use \texttt{a < b} (or any other comparison), as that will return an array of booleans.
|
||||
|
||||
For piecewise interpolation, a useful method is \texttt{np.searchsorted(arr.flat, vals\_insert, side='right')}, where \texttt{vals\_insert} are the values to be inserted
|
||||
and the \texttt{side} argument indicates on which side of the match they are to be inserted.
|
||||
|
||||
For that though, the array needs to be sorted, for which we can use \texttt{np.argsort(arr, axis=-1)}.
|
||||
This will return the indices in the order that would sort the array along the given axis. If axis is unspecified, \texttt{-1} is used.
|
||||
To use these indices to sort an array, we can simply use \texttt{arr[np.argsort(arr)]}.
|
||||
|
||||
|
||||
Slicing and indexing works just as in Python (assume \texttt{a} is a numpy array):
|
||||
\begin{code}{python}
|
||||
a = np.arange(10)
|
||||
print(a[2]) # Outputs 2 (third element)
|
||||
print(a[-1]) # Outputs 9 (last element)
|
||||
print(a[-2]) # Outputs 8 (2nd to last element)
|
||||
print(a[2:5]) # Outputs [2, 3, 4] (elements 2, 3, and 4)
|
||||
print(a[2:5:-1]) # Outputs [4, 3, 2] (reversed)
|
||||
print(a[::-1]) # Reverses the array
|
||||
\end{code}
|
||||
So, the basic syntax for slicing is \texttt{a[start : stop : step]} and any of them can be omitted, though the corresponding colons cannot be omitted if you omit start.
|
||||
|
||||
We can also iterate over a numpy array normally (the iterator variable will be the \texttt{i}-th element of the outermost array of the numpy array).
|
||||
To iterate over all elements of the array (i.e. the actual data values), we can use \texttt{arr.flat} to get a view (similar to a reference, not copied) that has
|
||||
length that corresponds to the sum of all elements of \texttt{arr.shape}.
|
||||
|
||||
For \texttt{n}-d arrays, we can use \texttt{a[0, 1]} to access element \texttt{a[0][1]}, which is more efficient.
|
||||
|
||||
|
||||
\subsubsection{Shape manipulation}
|
||||
We can reshape an array by using \texttt{arr.reshape(dim1, dim2, \dots)}. This however returns the array with modified shape,
|
||||
whereas \texttt{arr.resize((dim1, dim2, \dots))} modifies the array directly (notice that here we have to pass a tuple!)
|
||||
|
||||
To get a one-dimensional array, we can use \texttt{arr.ravel()}, after which the array looks the same
|
||||
as \texttt{arr.flat}, but the change is permanent
|
||||
|
||||
|
||||
\fhlc{Cyan}{Stacking arrays}
|
||||
|
||||
\texttt{np.vstack((a, b))} adds array \texttt{b}'s elements to array \texttt{a} (i.e. stacks along \texttt{axis=0}).
|
||||
\texttt{np.hstack((a, b))} adds array \texttt{b}'s elements to the inner arrays of \texttt{a} (i.e. stacks along \texttt{axis=1}).
|
||||
\texttt{np.concatenate((a, b, \dots), axis=n)} does as the above, but applies it to axis \texttt{n}
|
||||
|
||||
\fhlc{Cyan}{Splitting arrays}
|
||||
|
||||
\texttt{np.hsplit(a, count)} splits \texttt{a} into \texttt{count} arrays (along \texttt{axis=0})
|
||||
\texttt{np.vsplit(a, count)} splits \texttt{a} into \texttt{count} arrays (along \texttt{axis=1})
|
||||
\texttt{np.array\_split(a, count, axis=n)} splits \texttt{a} into \texttt{count} arrays (along \texttt{axis=n})
|
||||
8
semester3/numcs/parts/06_python/02_scipy.tex
Normal file
8
semester3/numcs/parts/06_python/02_scipy.tex
Normal file
@@ -0,0 +1,8 @@
|
||||
\newpage
|
||||
\subsection{Scipy}
|
||||
Scipy is a library that, according to its website, provides ``Fundamental algorithms for scientific computing in Python''.
|
||||
In this course it is primarily used for cases where Numpy either does not have an implementation or SciPy's implementation is faster.
|
||||
|
||||
Scipy needs Numpy arrays as inputs in most cases, thus not requiring any additional syntax.
|
||||
|
||||
You can find the scipy reference docs \hlhref{https://docs.scipy.org/doc/scipy/reference/index.html}{here}
|
||||
15
semester3/numcs/parts/06_python/03_sympy-ex.py
Normal file
15
semester3/numcs/parts/06_python/03_sympy-ex.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import sympy as sp
|
||||
|
||||
a, b = (0, 1);
|
||||
x, y = sp.symbols("x, y") # Create sympy symbols
|
||||
f = x**2 + 3 * x - 2 # Create your function
|
||||
# In the below, for 1D differentiation, we can omit the symbol and just use sp.diff(f)
|
||||
df = sp.diff(f, x) # Add more arguments for derivatives in other variables
|
||||
F = sp.integrate(f, x) # Integrates the function analytically in x
|
||||
F = sp.integrate(f, (x, a, b)) # Indefinite integral in x in interval [a, b]
|
||||
lambda_f = sp.lambdify(x, F) # Creates a lambda function of F in variable x
|
||||
lambda_f = sp.lambdify([x, y], F) # Creates a lambda function of F in variables x and y
|
||||
roots = sp.roots(f) # Computes the roots of function f analytically
|
||||
sp.hermite_poly(5) # Creates hermite poly of degree 5
|
||||
sp.chebyshevt_poly(5) # Creates chebychev T (first kind) poly of degree 5
|
||||
sp.chebyshevu_poly(5) # Creates chebychev U (second kind) poly of degree 5
|
||||
6
semester3/numcs/parts/06_python/03_sympy.tex
Normal file
6
semester3/numcs/parts/06_python/03_sympy.tex
Normal file
@@ -0,0 +1,6 @@
|
||||
\subsection{Sympy}
|
||||
\label{sec:sympy}
|
||||
Sympy can be used to do symbolic operations, i.e. similar to what we would do in Analysis or the like.
|
||||
|
||||
You usually want to follow something like the below code:
|
||||
\inputcode{python}{parts/06_python/03_sympy-ex.py}
|
||||
Reference in New Issue
Block a user