%%html
<iframe width="560" height="315" src="https://www.youtube.com/embed/HW29067qVWk" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
%load_ext version_information
%version_information numpy, scipy, sympy, matplotlib, version_information
Software | Version |
---|---|
Python | 3.9.2 64bit [GCC 9.3.0] |
IPython | 7.21.0 |
OS | Linux 4.19.0 14 amd64 x86_64 with glibc2.28 |
numpy | 1.20.1 |
scipy | 1.6.0 |
sympy | 1.7.1 |
matplotlib | 3.3.4 |
version_information | 1.0.3 (fixed) |
Tue Mar 16 23:24:55 2021 CET |
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
plt.show()
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(10,5))
df
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 1.244373 | -2.375276 | -1.249719 | 0.666848 | 0.917400 |
1 | -0.299879 | -0.886450 | 0.460110 | -0.546190 | 0.340645 |
2 | -1.110623 | -0.544608 | 0.977602 | -2.100853 | 0.234692 |
3 | 1.329575 | 0.341214 | 0.360423 | -1.110605 | 0.690054 |
4 | 1.037706 | -1.841255 | -2.410571 | 0.249865 | 0.705019 |
5 | -2.255515 | 0.092135 | 1.094941 | 0.150178 | -1.117143 |
6 | 0.962582 | 1.498060 | 1.738207 | -0.526848 | 0.337179 |
7 | 0.069187 | -1.550710 | 0.096162 | -0.250829 | 1.040123 |
8 | 0.533513 | -0.818389 | 3.267903 | 0.171266 | -0.786601 |
9 | 0.837141 | 1.124104 | -0.587130 | -0.399321 | -1.489129 |
from __future__ import division
from IPython.display import display
from sympy.interactive import printing
printing.init_printing(use_latex='mathjax')
import sympy as sym
from sympy import *
x, y, z = symbols("x y z")
k, m, n = symbols("k m n", integer=True)
f, g, h = map(Function, 'fgh')
Rational(3,2)*pi + exp(I*x) / (x**2 + y)
exp(I*x).subs(x,pi).evalf()
e = x + 2*y
srepr(e)
"Add(Symbol('x'), Mul(Integer(2), Symbol('y')))"
exp(pi * sqrt(163)).evalf(50)
eq = ((x+y)**2 * (x+1))
eq
expand(eq)
a = 1/x + (x*sin(x) - 1)/x
a
simplify(a)
eq = Eq(x**3 + 2*x**2 + 4*x + 8, 0)
eq
solve(eq, x)
a, b = symbols('a b')
Sum(6*n**2 + 2**n, (n, a, b))
limit((sin(x)-x)/x**3, x, 0)
(1/cos(x)).series(x, 0, 6)
diff(cos(x**2)**2 / (1+x), x)
integrate(x**2 * cos(x), (x, 0, pi/2))
eqn = Eq(Derivative(f(x),x,x) + 9*f(x), 1)
display(eqn)
dsolve(eqn, f(x))
We will define a function to compute the Taylor series expansions of a symbolically defined expression at various orders and visualize all the approximations together with the original function
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# You can change the default figure size to be a bit larger if you want,
# uncomment the next line for that:
#plt.rc('figure', figsize=(10, 6))
def plot_taylor_approximations(func, x0=None, orders=(2, 4), xrange=(0,1), yrange=None, npts=200):
"""Plot the Taylor series approximations to a function at various orders.
Parameters
----------
func : a sympy function
x0 : float
Origin of the Taylor series expansion. If not given, x0=xrange[0].
orders : list
List of integers with the orders of Taylor series to show. Default is (2, 4).
xrange : 2-tuple or array.
Either an (xmin, xmax) tuple indicating the x range for the plot (default is (0, 1)),
or the actual array of values to use.
yrange : 2-tuple
(ymin, ymax) tuple indicating the y range for the plot. If not given,
the full range of values will be automatically used.
npts : int
Number of points to sample the x range with. Default is 200.
"""
if not callable(func):
raise ValueError('func must be callable')
if isinstance(xrange, (list, tuple)):
x = np.linspace(float(xrange[0]), float(xrange[1]), npts)
else:
x = xrange
if x0 is None: x0 = x[0]
xs = sym.Symbol('x')
# Make a numpy-callable form of the original function for plotting
fx = func(xs)
f = sym.lambdify(xs, fx, modules=['numpy'])
# We could use latex(fx) instead of str(), but matploblib gets confused
# with some of the (valid) latex constructs sympy emits. So we play it safe.
plt.plot(x, f(x), label=str(fx), lw=2)
# Build the Taylor approximations, plotting as we go
apps = {}
for order in orders:
app = fx.series(xs, x0, n=order).removeO()
apps[order] = app
# Must be careful here: if the approximation is a constant, we can't
# blindly use lambdify as it won't do the right thing. In that case,
# evaluate the number as a float and fill the y array with that value.
if isinstance(app, sym.core.numbers.Number):
y = np.zeros_like(x)
y.fill(app.evalf())
else:
fa = sym.lambdify(xs, app, modules=['numpy'])
y = fa(x)
tex = sym.latex(app).replace('$', '')
plt.plot(x, y, label=r'$n=%s:\, %s$' % (order, tex) )
# Plot refinements
if yrange is not None:
plt.ylim(*yrange)
plt.grid()
plt.legend(loc='best').get_frame().set_alpha(0.8)
With this function defined, we can now use it for any sympy function or expression
plot_taylor_approximations(sin, 0, [2, 4, 6], (0, 2*pi), (-2,2))
plot_taylor_approximations(cos, 0, [2, 4, 6], (0, 2*pi), (-2,2))
This shows easily how a Taylor series is useless beyond its convergence radius, illustrated by a simple function that has singularities on the real axis:
# For an expression made from elementary functions, we must first make it into
# a callable function, the simplest way is to use the Python lambda construct.
plot_taylor_approximations(lambda x: 1/cos(x), 0, [2,4,6], (0, 2*pi), (-5,5))
A simple illustration of the trapezoid rule for definite integration:
$$ \int_{a}^{b} f(x)\, dx \approx \frac{1}{2} \sum_{k=1}^{N} \left( x_{k} - x_{k-1} \right) \left( f(x_{k}) + f(x_{k-1}) \right). $$
First, we define a simple function and sample it between 0 and 10 at 200 points
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
def f(x):
return (x-3)*(x-5)*(x-7)+85
x = np.linspace(0, 10, 200)
y = f(x)
Choose a region to integrate over and take only a few points in that region
a, b = 1, 8 # the left and right boundaries
N = 5 # the number of points
xint = np.linspace(a, b, N)
yint = f(xint)
Plot both the function and the area below it in the trapezoid approximation
plt.plot(x, y, lw=2)
plt.axis([0, 9, 0, 140])
plt.fill_between(xint, 0, yint, facecolor='gray', alpha=0.4)
plt.text(0.5 * (a + b), 30,r"$\int_a^b f(x)dx$", horizontalalignment='center', fontsize=20);
Compute the integral both at high accuracy and with the trapezoid approximation
from __future__ import print_function
from scipy.integrate import quad
integral, error = quad(f, a, b)
integral_trapezoid = sum( (xint[1:] - xint[:-1]) * (yint[1:] + yint[:-1]) ) / 2
print("The integral is:", integral, "+/-", error)
print("The trapezoid approximation with", len(xint), "points is:", integral_trapezoid)
The integral is: 565.2499999999999 +/- 6.275535646693696e-12 The trapezoid approximation with 5 points is: 559.890625