Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download
Views: 560
Kernel: Python 3 (Anaconda)

SciPy

Što je SciPy?

SciPy je nadgradnja NumPy paketa, i sadrži veliki broj numeričkih algoritama za cijeli niz područja. Ovdje su pobrojana neka nama zanimljivija:

Za zadnja dva područja postoje i napredniji paketi. Za slike smo već npr. koristili scikit-image), a za statistiku ćemo korititi pandas paket.

SciPy paket učitavamo pomoću scipy modula.

from scipy import *

Narvno, možemo učitati i samo podpaket koji nas zanima, u ovom slučaju za linearnu algebru.

import scipy.linalg as la

Specijalne funkcije

Kao primjer pogledajmo Besselove funkcije:

# jn, yn: Besselove funkcije prvog i drugog reda s realnim stupnjem # jn_zeros, yn_zeros: računaju pripadne nultočke from scipy.special import jn, yn, jn_zeros, yn_zeros
n = 0 # stupanj x = 0.0 print ("J_{}({}) = {:f}".format(n, x, jn(n, x))) x = 1.0 print ("Y_{}({}) = {:f}".format(n, x, yn(n, x)))
J_0(0.0) = 1.000000 Y_0(1.0) = 0.088257
from pylab import * %matplotlib inline
x = linspace(0, 10, 100) fig, ax = subplots() for n in range(4): ax.plot(x, jn(n, x), label=r"$J_%d(x)$" % n) ax.legend();
Image in a Jupyter notebook
n = 0 # stupanj m = 4 # broj nultočaka za izračunati jn_zeros(n, m)
array([ 2.40482556, 5.52007811, 8.65372791, 11.79153444])

Numerička integracija

from scipy.integrate import quad, dblquad, tplquad

quad funkcija se koriste za numeričku integracije (quad ... jer se na engleskom taj proces zove kvadratura). dblquad služi za dvostruke, a tplquad za trostruke integrale.

Jednostavan primjer, računamo 01xdx\begin{equation*} \int_0^1 x\, \mathrm{d}x \end{equation*}

def f(x): return x
x_donje = 0 x_gornje = 1 rez, abserr = quad(f, x_donje, x_gornje) print ("Rezultat = {}, apsolutna greška = {}".format(rez,abserr))
Rezultat = 0.5, apsolutna greška = 5.551115123125783e-15

Ove funkcije imaju puno opcionalnih argumenata. Ako želimo funkciji koju integriramo proslijediti dodatne parametre (vidi ovdje), možemo korisiti varijablu args.

def integrand(x, n): """ Besselova funkcija prvog tipa stupnja n. """ return jn(n, x) x_d = 0 x_g = 10 rez, abserr = quad(integrand, x_d, x_g, args=(3,)) print (rez, abserr)
0.7366751370811073 9.389126882496403e-13

Korištenje anonimnih funkcija:

rez, abserr = quad(lambda x: exp(-x ** 2), -Inf, Inf) print ("numerički = {}, {}".format(rez, abserr)) egzaktno = sqrt(pi) print ("egzaktno = {}".format(egzaktno))
numerički = 1.7724538509055159, 1.4202636780944923e-08 egzaktno = 1.7724538509055159

U više dimenzija:

abg(x)h(x)f(x,y)dydx\begin{equation*} \int_a^b \int_{g(x)}^{h(x)} f(x,y)\,\mathrm{d}y\mathrm{d}x \end{equation*}
def integrand(x, y): return exp(-x**2-y**2) x_d = 0 x_g = 10 y_d = 0 y_g = 10 # ovdje je a = x_d, b = x_g, g(x) = y_d, h(x) = y_g # g(x) i h(x) trebaju biti funkcije! rez, abserr = dblquad(integrand, x_d, x_g, lambda x : y_d, lambda x: y_g) print (rez, abserr)
0.7853981633974476 1.3753098510218528e-08

Obične diferencijalne jednadžbe (ODJ)

SciPy nudi dvije mogućnosti rješavanja ODJ: Funkciju odeint i klasu ode. Mi ćemo prikazati odeint.

from scipy.integrate import odeint, ode

Sustav ODJ zapisujemo kao:

y=f(y,t)y' = f(y, t)

gdje je

y=[y1(t),y2(t),...,yn(t)]y = [y_1(t), y_2(t), ..., y_n(t)],

Još trebamo i početne uvjete y(0)y(0).

Ovo je sintaksa:

y_t = odeint(f, y_0, t)
  • t je niz vremena za koje želimo riješiti ODJ

  • y_t je niz s jednim retkom za svaki trenutak iz t, a stupci daje rješenje y_i(t) u tom trenutku

Dvostruko njihalo

from IPython.display import Image Image(url='http://upload.wikimedia.org/wikipedia/commons/c/c9/Double-compound-pendulum-dimensioned.svg')

Ovo su jednadže s wiki stranice:

θ˙1=6m22pθ13cos(θ1θ2)pθ2169cos2(θ1θ2){\dot \theta_1} = \frac{6}{m\ell^2} \frac{ 2 p_{\theta_1} - 3 \cos(\theta_1-\theta_2) p_{\theta_2}}{16 - 9 \cos^2(\theta_1-\theta_2)}

θ˙2=6m28pθ23cos(θ1θ2)pθ1169cos2(θ1θ2).{\dot \theta_2} = \frac{6}{m\ell^2} \frac{ 8 p_{\theta_2} - 3 \cos(\theta_1-\theta_2) p_{\theta_1}}{16 - 9 \cos^2(\theta_1-\theta_2)}.

p˙θ1=12m2[θ˙1θ˙2sin(θ1θ2)+3gsinθ1]{\dot p_{\theta_1}} = -\frac{1}{2} m \ell^2 \left [ {\dot \theta_1} {\dot \theta_2} \sin (\theta_1-\theta_2) + 3 \frac{g}{\ell} \sin \theta_1 \right ]

p˙θ2=12m2[θ˙1θ˙2sin(θ1θ2)+gsinθ2]{\dot p_{\theta_2}} = -\frac{1}{2} m \ell^2 \left [ -{\dot \theta_1} {\dot \theta_2} \sin (\theta_1-\theta_2) + \frac{g}{\ell} \sin \theta_2 \right]

Definiramo:

x=[θ1,θ2,pθ1,pθ2]x = [\theta_1, \theta_2, p_{\theta_1}, p_{\theta_2}]

g = 9.82 L = 0.5 m = 0.1 def dx(x, t): """ Desna strana ODJ """ x1, x2, x3, x4 = x[0], x[1], x[2], x[3] dx1 = 6.0/(m*L**2) * (2 * x3 - 3 * cos(x1-x2) * x4)/(16 - 9 * cos(x1-x2)**2) dx2 = 6.0/(m*L**2) * (8 * x4 - 3 * cos(x1-x2) * x3)/(16 - 9 * cos(x1-x2)**2) dx3 = -0.5 * m * L**2 * ( dx1 * dx2 * sin(x1-x2) + 3 * (g/L) * sin(x1)) dx4 = -0.5 * m * L**2 * (-dx1 * dx2 * sin(x1-x2) + (g/L) * sin(x2)) return [dx1, dx2, dx3, dx4]
# početni uvjet x0 = [pi/4, pi/2, 0, 0]
# niz vremena t = linspace(0, 10, 250)
# rješenje ODJ x = odeint(dx, x0, t)
# nacrtajmo rješenje # crtamo kuteve fig, axes = subplots(1,2, figsize=(12,4)) axes[0].plot(t, x[:, 0], 'r', label="theta1") axes[0].plot(t, x[:, 1], 'b', label="theta2") x1 = + L * sin(x[:, 0]) y1 = - L * cos(x[:, 0]) x2 = x1 + L * sin(x[:, 1]) y2 = y1 - L * cos(x[:, 1]) axes[1].plot(x1, y1, 'r', label="njihalo1") axes[1].plot(x2, y2, 'b', label="njihalo2") axes[1].set_ylim([-1, 0]) axes[1].set_xlim([1, -1]);
Image in a Jupyter notebook

Jednostavna animacija, kasnije ćemo vidjeti kako možemo napravit bolju animaciju.

from IPython.display import display,clear_output import time
fig, ax = subplots(figsize=(4,4)) for t_idx, tt in enumerate(t[:200]): x1 = + L * sin(x[t_idx, 0]) y1 = - L * cos(x[t_idx, 0]) x2 = x1 + L * sin(x[t_idx, 1]) y2 = y1 - L * cos(x[t_idx, 1]) ax.cla() ax.plot([0, x1], [0, y1], 'r.-') ax.plot([x1, x2], [y1, y2], 'b.-') ax.set_ylim([-1.5, 0.5]) ax.set_xlim([1, -1]) display(fig) clear_output(wait=True) time.sleep(0.03)
Image in a Jupyter notebook

Prigušeni dinamički oscilator

Opis problema možete pročitati ovdje: http://en.wikipedia.org/wiki/Damping

Jednadžba je

d2xdt2+2ζω0dxdt+ω02x=0\begin{equation} \frac{\mathrm{d}^2x}{\mathrm{d}t^2} + 2\zeta\omega_0\frac{\mathrm{d}x}{\mathrm{d}t} + \omega^2_0 x = 0 \end{equation}
  • xx pozicija oscilatora,

  • ω0\omega_0 frekvencija,

  • ζ\zeta koeficijent gušenja.

Definiramo p=dxdtp = \frac{\mathrm{d}x}{\mathrm{d}t}:

dpdt=2ζω0pω02x\begin{equation} \frac{\mathrm{d}p}{\mathrm{d}t} = - 2\zeta\omega_0 p - \omega^2_0 x \end{equation}dxdt=p\begin{equation} \frac{\mathrm{d}x}{\mathrm{d}t} = p \end{equation}
def dy(y, t, zeta, w0): """ Desna strana ODJ za harmonički oscilator """ x, p = y[0], y[1] dx = p dp = -2 * zeta * w0 * p - w0**2 * x return [dx, dp]
# početno stanje: y0 = [1.0, 0.0]
# vremena, frekvencija t = linspace(0, 10, 1000) w0 = 2*pi*1.0
# rješavamo ODJ za tri vrste prigušenja y1 = odeint(dy, y0, t, args=(0.0, w0)) # negušeno y2 = odeint(dy, y0, t, args=(0.2, w0)) # podgušeno y3 = odeint(dy, y0, t, args=(1.0, w0)) # kritičko gušenje y4 = odeint(dy, y0, t, args=(5.0, w0)) # pregušeno
fig, ax = subplots() ax.plot(t, y1[:,0], 'k', label="negušeno", linewidth=0.25) ax.plot(t, y2[:,0], 'r', label="podgušeno") ax.plot(t, y3[:,0], 'b', label="kritičko gušenje") ax.plot(t, y4[:,0], 'g', label="pregušeno") ax.legend();
Image in a Jupyter notebook

Fourierova transformacija

Paket je fftpack:

from scipy.fftpack import *

Primjenimo Fourierovu transformaciju na prethodni primjer harmoničkog oscilatora.

N = len(t) dt = t[1]-t[0] # y2 je rješenje podgušenog harmoničkog oscilatora F = fft(y2[:,0]) # izračunajmo frekvencije w = fftfreq(N, dt)
fig, ax = subplots(figsize=(9,3)) ax.plot(w, abs(F));
Image in a Jupyter notebook

Kako je signal realan, spektar je simetričan. Stoga nam je dosta nacrtati pozitivne frekvencije.

indeksi = where(w > 0) w_pos = w[indeksi] F_pos = F[indeksi]
fig, ax = subplots(figsize=(9,3)) ax.plot(w_pos, abs(F_pos)) ax.set_xlim(0, 5);
Image in a Jupyter notebook

Linearna algebra

Detaljna dokumentacija: http://docs.scipy.org/doc/scipy/reference/linalg.html

Nećemo prolaziti kroz sve funkcije.

Sustavi linearnih jednadžbi

Ax=bA x = b

A = array([[1,2,-1], [4,5,6], [7,8,9]]) b = array([1,2,3])
x = solve(A, b) x
array([-0.33333333, 0.66666667, 0. ])
# provjera dot(A, x) - b
array([ 0.00000000e+00, -2.22044605e-16, 0.00000000e+00])

AX=BA X = B

A = rand(3,3) B = rand(3,3)
X = solve(A, B) X
array([[ 0.5199847 , 1.33508075, 0.98631147], [-0.85868255, -2.24599046, 0.53620857], [ 0.79516259, 0.18409863, -0.79258861]])
# provjera norm(dot(A, X) - B)
4.1910000110727263e-16

Svojstveni problem

Av=λv\begin{equation}\displaystyle A v = \lambda v\end{equation}
evals = eigvals(A) evals
array([ 1.16326497+0.j , -0.12471967+0.21365995j, -0.12471967-0.21365995j])
evals, evecs = eig(A)
evals
array([ 1.16326497+0.j , -0.12471967+0.21365995j, -0.12471967-0.21365995j])
evecs
array([[ 0.57615104+0.j , 0.31100815-0.18792585j, 0.31100815+0.18792585j], [ 0.55783043+0.j , -0.76806662+0.j , -0.76806662-0.j ], [ 0.59739031+0.j , -0.28786918+0.44177235j, -0.28786918-0.44177235j]])

Svojstveni vektori su stupci u evecs:

n = 1 norm(dot(A, evecs[:,n]) - evals[n] * evecs[:,n])
6.6772208449746893e-16

To nije sve, postoje i specijalizirane funkcije, kao npr. eigh za hermitske matrice

Matrične operacije

# inverz inv(A)
array([[ 0.18224249, 2.32018496, -1.51321686], [-0.76564105, -4.50039798, 5.74351864], [ 2.03427742, -2.36102176, 1.10236963]])
# determinanta det(A)
0.07119829516433468
# razne norme norm(A, ord=2), norm(A, ord=Inf)
(1.4186446775313915, 1.2152976994987217)

Rijetke matrice

Više informacija na http://en.wikipedia.org/wiki/Sparse_matrix

Postoji više formata rijetkih matrica, mi nećemo ulaziti u detalje.

from scipy.sparse import *
# gusta matrica M = array([[1,0,0,0], [0,3,0,0], [0,1,1,0], [1,0,0,1]]); M
array([[1, 0, 0, 0], [0, 3, 0, 0], [0, 1, 1, 0], [1, 0, 0, 1]])
# pretvorimo je u rijetku matricu A = csr_matrix(M); A
<4x4 sparse matrix of type '<class 'numpy.int64'>' with 6 stored elements in Compressed Sparse Row format>
# vratimo natrag A.todense()
matrix([[1, 0, 0, 0], [0, 3, 0, 0], [0, 1, 1, 0], [1, 0, 0, 1]], dtype=int64)

Pametniji način kreiranja rijetke matrice.

A = lil_matrix((4,4)) # prazna 4x4 rijetka matrica A[0,0] = 1 A[1,1] = 3 A[2,2] = A[2,1] = 1 A[3,3] = A[3,0] = 1 A
<4x4 sparse matrix of type '<class 'numpy.float64'>' with 6 stored elements in LInked List format>
A.todense()
matrix([[ 1., 0., 0., 0.], [ 0., 3., 0., 0.], [ 0., 1., 1., 0.], [ 1., 0., 0., 1.]])
# konvertiranje A = csr_matrix(A); A
<4x4 sparse matrix of type '<class 'numpy.float64'>' with 6 stored elements in Compressed Sparse Row format>
A = csc_matrix(A); A
<4x4 sparse matrix of type '<class 'numpy.float64'>' with 6 stored elements in Compressed Sparse Column format>
A.todense()
matrix([[ 1., 0., 0., 0.], [ 0., 3., 0., 0.], [ 0., 1., 1., 0.], [ 1., 0., 0., 1.]])
(A * A).todense()
matrix([[ 1., 0., 0., 0.], [ 0., 9., 0., 0.], [ 0., 4., 1., 0.], [ 2., 0., 0., 1.]])
(A @ A).todense()
matrix([[ 1., 0., 0., 0.], [ 0., 9., 0., 0.], [ 0., 4., 1., 0.], [ 2., 0., 0., 1.]])
dot(A,A)
<4x4 sparse matrix of type '<class 'numpy.float64'>' with 6 stored elements in Compressed Sparse Column format>
v = array([1,2,3,4])[:,newaxis]; v
array([[1], [2], [3], [4]])

Vektor v smo mogli konstruirati i drugačije (vidjeli smo primjere u predavanju o NumPy-ju), no uvijek trebamo doći do dvodimenzionalnog niza. Za razliku od MATLAB-a u kojemu su svi nizovi 2D, u NumPy-ju 1D niz nije isto što i matrica n×1n\times 1 ili 1×n1\times n. Npr. jedna mogućnost je

v = array([[1,2,3,4]]).T
# rijetka matrica puta vektor A * v
array([[ 1.], [ 6.], [ 5.], [ 5.]])
A.todense() * v
matrix([[ 1.], [ 6.], [ 5.], [ 5.]])
from scipy import optimize

Nalaženje minimuma

def f(x): return 4*x**3 + (x-2)**2 + x**4
fig, ax = subplots() x = linspace(-5, 3, 100) ax.plot(x, f(x));
Image in a Jupyter notebook
x_min = optimize.fmin_bfgs(f, -2) x_min
Optimization terminated successfully. Current function value: -3.506641 Iterations: 5 Function evaluations: 24 Gradient evaluations: 8
array([-2.67298151])
optimize.fmin_bfgs(f, 0.5)
Optimization terminated successfully. Current function value: 2.804988 Iterations: 3 Function evaluations: 15 Gradient evaluations: 5
array([ 0.46961745])
optimize.brent(f)
0.46961743402759754
optimize.fminbound(f, -4, 2)
-2.6729822917513886

Nalaženje rješenja jednadžbi

Problem oblika f(x)=0f(x) = 0 se rješava fsolve funkcijom.

omega_c = 3.0 def f(omega): return tan(2*pi*omega) - omega_c/omega
import numpy as np np.seterr(divide='ignore') fig, ax = subplots(figsize=(10,4)) x = linspace(0, 3, 1000) y = f(x) maska = where(abs(y) > 50) x[maska] = y[maska] = NaN # da se riješimo asimptote ax.plot(x, y) ax.plot([0, 3], [0, 0], 'k') ax.set_ylim(-5,5);
Image in a Jupyter notebook
optimize.fsolve(f, 0.1)
array([ 0.23743014])
optimize.fsolve(f, 0.6)
array([ 0.71286972])
optimize.fsolve(f, 1.1)
array([ 1.18990285])

Interpolacija

Funkcija interp1d, za dane nizove xx i yy koordinata vraća objekt koji se ponaša kao funkcija.

from scipy.interpolate import *
n = arange(0, 10) x = linspace(0, 9, 100) y_meas = sin(n) + 0.1 * randn(len(n)) # ubacujemo malo šuma y_real = sin(x) linear_interpolation = interp1d(n, y_meas) y_interp1 = linear_interpolation(x) cubic_interpolation = interp1d(n, y_meas, kind='cubic') y_interp2 = cubic_interpolation(x)
fig, ax = subplots(figsize=(10,4)) ax.plot(n, y_meas, 'bs', label='podaci sa šumom') ax.plot(x, y_real, 'k', lw=2, label='originalna funkcija') ax.plot(x, y_interp1, 'r', label='linearna interpolacija') ax.plot(x, y_interp2, 'g', label='kubična interpolacija') ax.legend(loc=3);
Image in a Jupyter notebook

Statistika

Više na http://docs.scipy.org/doc/scipy/reference/stats.html.

Mi ćemo kasnije raditi s moćnijim paketom pandas.

from scipy import stats
# slučajna varijabla s Poissionovom distribucijom X = stats.poisson(3.5)
n = arange(0,15) fig, axes = subplots(2,1, sharex=True) # kumulativna distribucija (CDF) axes[0].step(n, X.cdf(n)) # histogram 1000 slučajnih realizacija od X axes[1].hist(X.rvs(size=1000));
Image in a Jupyter notebook
# normalna distribucija Y = stats.norm()
x = linspace(-5,5,100) fig, axes = subplots(3,1, sharex=True) # PDF axes[0].plot(x, Y.pdf(x)) # CDF axes[1].plot(x, Y.cdf(x)); # histogram axes[2].hist(Y.rvs(size=1000), bins=50);
Image in a Jupyter notebook

Osnovna statistika:

X.mean(), X.std(), X.var()
(3.5, 1.8708286933869707, 3.5)
Y.mean(), Y.std(), Y.var()
(0.0, 1.0, 1.0)
from verzije import * from IPython.display import HTML HTML(print_sysinfo()+info_packages('numpy,scipy,matplotlib'))
Python verzija3.5.3
kompajlerGCC 4.8.2 20140120 (Red Hat 4.8.2-15)
sustavLinux
broj CPU-a8
interpreter64bit
numpy verzija1.11.3
scipy verzija0.19.0
matplotlib verzija2.0.0

Zadaci za vježbu

  • Konstruirajte 1000×10001000\times 1000 matricu tipa lil_matrix, konvertirajte je u CSR format i riješite Ax=bA x = b za neki bb.

  • Učitajte matricu ODEP400A te izračunajte 100 njenih svojstvenih vrijednosti.

  • Zadana je funkcija f(x,y)=exp(1/(0.1x2+y2)f(x,y)=\mathrm{exp}(-1/(0.1x^2 + y^2). Ta funkcija ima minimum u (0,0)(0,0). Krenuvši od početne točke (1,1)(1, 1), probajte doći 10810^{-8} blizu minimuma koristeći funkcije za optimizaciju.

  • Riješite Lotka-Volterrin sustav ODJ za različite parametre α\alpha, β\beta, γ\gamma, δ\delta.

  • Riješite sljedeći problem: minx1x4(x1+x2+x3)+x3x1x2x3x425x12+x22+x32+x42=401x1,x2,x3,x45\begin{gather} \min x_1 x_4 (x_1+x_2+x_3)+x_3 \\ x_1x_2x_3x_4 \ge 25 \\ x_1^2 + x_2^2 + x_3^2 +x_4^2 =40 \\ 1 \le x_1,x_2,x_3,x_4 \le 5 \end{gather} Za početnu točku uzmite x0=(1,5,5,1)x_0 =(1,5,5,1).

Slika moonlanding.png je puna šuma. Zadaća je očistiti sliku koristeći Fourierovu transformaciju.

  • Učitajte sliku s pylab.imread().

  • Nađite i iskoristite 2-D FFT funkciju iz scipy.fftpack i nacrtajte spektar slike.

  • Spektar se sastoji od komponenti s viskom i niskom frekvencijom. Šum je smješten u dijelu spektra s visokom frekvencijom, pa probajte neke od tih komponenti staviti na nulu.

  • Koristite inverznu Fourierovu transformaciju da pogledate da li ste napravili dobar posao.