csomag | |
---|---|
NumPy | Hatékony N-dimenziós tömb |
SciPy | Numerikus számítások |
Matplotlib | Grafikonok és rajzok |
IPython (Jupyter) | Interaktív notebook |
SymPy | Szimbolikus számítások |
Pandas | Adatbányászat |
A Python Scientific stack (és sok más) alap modulja.
import numpy as np
¶import numpy as np
A numpy központi objektuma az ndarray
($n$-dimenziós tömb).
A = np.array([[1, 2], [3, 4], [5, 6]])
A
type(A)
A.shape
egy tuple a tömb dimenzióival, alakjával.
A.shape
A listákkal ellentétben nem tárolhatunk benne bármit!
A dtype
megadja a tárolt elemek típusát
A.dtype
a=10**30 #Ez sima ügy
#A[0,0]=10**30 #Ez túl nagy lenne
A = np.array([1.5, 2])
A.dtype
A = np.array([[1, 2], [3, 4], [5, 6]])
A[0], A[1]
A[:, 0]
A[2, 1], type(A[2, 1])
A[:2] # vagy A[:2, :]
A[:, 1:]
A[::2]
B = np.array([[[1, 2, 3],[4, 5, 6]]])
B.shape, B.ndim
B
B[0].shape
B[0, 1], B[0, 1].shape
B[0, 1, 2]
A = np.array([[1, 1], [2, 2]])
P = A >= 2
print(P)
print(P.dtype)
A + A
A * A
A leggyakrabban használt matematikai fügvények is elérhetőek és elemenként hatnak.
np.exp(A)
np.sin(A*np.pi/6)
2**A
1/A
A=np.array([1,1,1,0]) & np.array([1,0,1,1])
A
A=np.array([1,1,1,0]) | np.array([1,0,1,1])
A
A dot
a szokásos mátrix szorzás
A = np.array([[1, 2], [3, 4]])
A.dot(A)
A @ A
A belső dimenzióknak passzolniuk kell
B = np.array([[1, 2, 3], [4, 5, 6]])
print(A.shape, B.shape)
A.dot(B)
#B.dot(A)
Tudunk invertálni, de mint mindig, figyelni kell a kerkítési hibákra.
A_inv = np.linalg.inv(A)
print(A_inv)
A_inv.dot(A)
np.round(A_inv.dot(A),5)
Nem négyzetes mátrixokra pseudo-inverzet is tuduni számolni.
A = np.array([[1, 2, 3], [4, 5, 6]])
A_pinv = np.linalg.pinv(A)
A.dot(A_pinv).dot(A)
(Van egy matrix
osztály is, ahol a *
használható mátrix szorzásra. De folyamatban van a numpyból való eltávolítása, úgyhogy ne használjátok.)
M = np.matrix([[1, 2], [3, 4]])
print(np.multiply(M, M)) # elemenként
print(M * M) # szokásos mátrix szorzás
A C nyelv típusai elérhetőek numpy
-ban.
P = np.array([[1.2, 1], [1.5, 0]])
print(P.dtype)
P.astype(int)
(-P.astype(int)).astype("uint32")
np.array([[1, 2], [3, 4]], dtype="float32")
A stringek számmá konvertálhatóak:
np.float32('-10'), np.float32(-10)
Megadhatjuk a dtype
-ot amikor létrehozzuk a tömböt.
np.array(['10', '20'], dtype="float32")
np.datetime64
¶Időpontok tárolására külön adattípus van.
np.datetime64("2018-03-10")
np.datetime64("2018-03-10") - np.datetime64("2017-12-13")
T = np.array(['körte', 'alma'])
print(T)
print(T.shape, T.dtype, type(T))
Fix hosszúságú karakter tömböket tárol!!
T[1] = "banana"
T
A :
az adott dimenzión belül mindent vesz.
A = np.array([[1, 2, 3], [4, 5, 6]])
print(A)
print(A[0])
print(A[0, :]) # első sor
print(A[:, 0]) # első oszlop
Ezek 1 dimenziós tömbök és nem $1\times n$-es vagy $n\times1$-es tömbök!
A[0, :].shape, A[:, 0].shape
B = np.array([[[1, 2, 3],[4, 5, 6]]])
B.shape
print(B[:, 1, :].shape)
B[:, 1, :]
B[0, 1, :], B[0, 1, :].shape
type(B[0, 1, 1]), B[0, 1, 1]
Minden eddigi python indexelési trükk működik:
A
print(A[:, ::-1])
print(A[::-1, :])
print(A[:, ::2])
Egy listával vagy tömbbel fogjuk megadni, hogy hanyadik elemeket szeretnénk.
B = np.array(["a","b","c","d","e","f","g"])
np.array([B[0],B[3],B[4],B[6]])
B[[0,3,4,6]] #gyorsabban ugyanaz
B[np.array([0,3,4,6])] #tömbbel ugyanaz
Több dimenzióban komplikálódnak a dolgok.
Ha egyetlen index tömbbel indexelünk, annak elemei megfelelnek M első kordináta szerint vett elemeinek.
M = np.arange(12).reshape(3,4)
M
np.array([[M[0],M[1]],[M[2],M[2]]])
M[np.array([[0,1],[2,2]])] #gyorsabban ugyanaz
Ha több index tömbbel indexelünk, akkor az első az első koordinátnak a második a másodiknak, ... felel meg.
np.array([M[0][2],M[1][2],M[1][0]])
np.array([M[0,2],M[1,2],M[1,0]])
M[np.array([0,1,1]),np.array([2,2,0])] #gyorsabban ugyanaz
np.array([[M[0,1],M[1,0]],[M[2,1],M[2,3]]])
M[np.array([[0,1],[2,2]]),np.array([[1,0],[1,3]])] #gyorsabban ugyanaz
M[:,[1,3]]
M[[1,2],:]
Többször is kiválaszthatjuk ugyanazt a sort vagy oszlopot:
M[[2,1,2],:]
Többdimenzióban még komplikáltabba a helyzet. https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html
A reshape
függvénnyel megváltoztathatjuk a tömb alakját anélkül, hogy a tartalmazott elemek megváltoznának, vagy akár lemásolódnának a hattérben.
B = np.array([[[1, 2, 3], [4, 5, 6]]])
B.reshape((2, 3))
B.reshape((3, 2))
ValueError
hibát kapunk ha rosz alakot adunk meg.
# B.reshape(7) # raises ValueError
np.array(range(6)).reshape((1, 2, 3))
Ha -1
-et adunk meg, megpróbálja kitalálni, hogy annak a dimenziónak mekkorának kell lennie az elemek száma alapján.
X = np.array(range(12)).reshape((2, -1, 2))
print("X.shape:", X.shape)
print(X)
A resize
akkor is működik, ha az elemek száma nem passzol. Ilyenkor töröl, vagy feltölt nullákkal. Magát a tömböt változtatja meg.
X = np.array([[1, 2], [3, 4]])
X.resize((5, 3))
X.resize((1, 2))
X
Viszont a np.resize
máshogy működik.
X = np.array([[1, 2], [3, 4]])
np.resize(X, (5, 3))
Ez nem a tömb metódusa! X
nem változik:
X
Ritkán akarjuk egyesével megadni az elemeket, ezért van egy csomó gyorsabb módszer:
arange
: range megfelelője csak nem listát hoz létre, hanem tömböt.linspace
: egyenletesen felosztott intervallumones
, ones_like
, csupa egyeszeros
, zeros_like
, csupa nullaeye
: indetitás mátrix 2 dimenzióbanfromfunction
függvény alapjánAz np.ones_like()
és np.zeros_like()
függvények megtartják a formát és a dtype
-ot!
np.arange(10), np.arange(10).shape
np.arange(1, 21, 2).reshape(5, -1)
np.linspace(0, 4, 11)
np.ones((3, 2)) * 5
np.zeros((2, 3,2))
A = np.arange(6).reshape(3, -1)
np.zeros_like(A)
np.eye(5)
np.eye(4, dtype=bool)
Az egyik leghasznosabb, hogy az indexek függvényében is definiálhatjuk a tömböt:
np.fromfunction(lambda i, j: i == j, (3, 3), dtype=int)
np.fromfunction(lambda i,j: 100*i+j, (5,5))
Bármelyik dimenzió szerint ragaszthatunk, ha megfelelőek a dimenziók.
A = np.arange(6).reshape(2, -1)
B = np.arange(8).reshape(2, -1)
np.concatenate((A, B), axis=1)
np.concatenate((A, B), axis=-1) # last dimension
#np.concatenate((A, B)) # axis=0 a default
Mivel általában az első vagy második koordináta szerint ragasztunk, ezekre vannak rövidítések:
A = np.arange(6).reshape(2, -1)
B = np.arange(8).reshape(2, -1)
np.hstack((A, B))
A = np.arange(6).reshape(-1, 2)
B = np.arange(8).reshape(-1, 2)
print(A.shape, B.shape)
np.vstack((A, B))
A.T
np.stack
egy új dimenzió szerint egymás mellé rakja a tömböket
A.shape, np.stack((A, A, A, A)).shape
np.stack((A, A, A, A))
Blokk mátrix készítés:
np.concatenate([np.concatenate([np.ones((2,2)), np.zeros((2,2))], axis=1),
np.concatenate([np.zeros((2,2)), np.ones((2,2))], axis=1)], axis=0)
Alapból az első koordináta szerint van iterálás:
A = np.arange(6).reshape(2, -1)
for row in A:
print(row)
De természetesen csinálhatunk ilyet:
B = np.arange(6).reshape(1, 2, 3)
for x in B[0, 0, :]:
print(x)
És végigiterálhatunk az összes elemen is:
for a in B.flat:
print(a)
for k in range(B.shape[2]):
print(B[:, :, k])
Különböző méretű tömbökkel is tudunk műveleteket végrehajtani, ha az alakjaik megfelelnek néhány feltételnek.
Például egy $1\times 1$-es tömb összesorozható egy több dimenziós tömbbel, mintha skalárral szoroznánk.
s = 2.0 * np.ones((1, 1))
A=np.arange(12).reshape(3,4)
print(s)
print(A)
s * A
De különböző méretű tömbökön nem tudsz elemenkénti műveletet végrehajtani:
# np.ones((2,3)) + np.ones((3,2))
Azt hogy mi történjen a broadcasting határozza meg. Ha valamelyik dimenzió mérete 1 akkor akkor az a dimenzió brodacastolható , azaz olyan széles lehet a dimenzió, amit a művelet akar.
np.arange(3).reshape((1,3)) + np.zeros((2, 3))
np.arange(3).reshape((3,1)) + np.zeros((3, 4))
Több dimenzió egyszerre is broadcastolható:
np.arange(3).reshape((1,3,1)) + np.zeros((2,3,5))
Ha mondjuk egy array alakja (1,3,1)
akkor az első és a harmadik dimenzió broadcastolható. Ekkor egy [x,y,z]
index hármast [0,y,0]
-ként értelmez a Python. Tehát a broadcastolt dimenziókban 0-nak tekintjük az indexet.
Nem létező dimenziókat is broadcastolhatunk, így lehet, hogy egy egydimenziós tömb összeadható egy két vagy háromdimenzióssal. Ekkor a hiányzó dimenziót elfelejtjük. Például egy ha az két tömb alakja (k,)
és (i, j, k)
és összadjuk őket akkor az (a,b,c)
indexből (c)
lesz. Tehát a kamu dimenziókat előre szúrjuk be.
def test_broadcast(x, y):
try:
A = np.ones(x) + np.ones(y)
print("Broadcastolható")
except ValueError:
print("Nem broadcastolható")
test_broadcast((3), (3,2,2))
test_broadcast((2), (3,2,2))
test_broadcast((3,1,4), (3,2,1))
test_broadcast((3,1,4), (3,2,2))
Meg is mondhatjuk, hogy hol hozzon létre új dimenziókat, a none
kulcsszóval.
(np.ones(3)[:, None, None] + np.ones((3,2,2)))
Tehát ekkor így változnak a dimenziók: (3, None, None) + (3, 2, 2) = (3, 2, 2)
Rács a komplex számsíkon:
np.arange(5)[:, None] + 1j * np.arange(5)[None, :]
Tengely menti szummázás:
Y = np.arange(24).reshape(2,3,4)
Y
Y.sum() # összes elem összege
Y.sum(axis=0)
Y.sum(axis=1)
mean, std, var
hasonlóan működik az átlag, szórás és szórásnégyzet kiszámolására.
Y.mean(),Y.std(),Y.var()
Y.mean(axis=(2, 0))
np.random
¶Numpynak van egy gazdag random számmokkal operáló alcsomagja.
A numpy.random.rand
például float64
számokat randomol a $[0, 1)$ intervallumról egyenletesen.
np.random.rand(2, 3).astype("float32")
Más eloszlások:
np.random.uniform(1, 2, (2, 2))
np.random.standard_normal(10)
np.random.normal(10, 1, size=(1,10))
Diszkrét eloszlások:
np.random.choice(["A", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "J", "Q", "K"], 5, replace=True)
choice
a valszóínűségeket is megadhatjuk:
np.random.choice(range(1, 7), 10,
p=[0.1, 0.1, 0.1, 0.1, 0.1, 0.5])
print(np.random.permutation(["A", "2", "3", "4", "5", "6",
"7", "8", "9", "10", "J", "Q", "K"]))
A permutation
az első dimenzió szerint permutál.
print(np.random.permutation(np.arange(9).reshape((3, 3))))
Feltételnek megfelelő elemek kiválasztása:
A = np.random.random((4, 3))
print(A.mean())
A
Az átlagnál nagyobb elemek:
A[A > A.mean()]
A > A.mean()
np.where
visszatér azokkal a tömbökkel, amik a speckó indexeléshez kellenek, ha a feltételnek megfelelő elemeket akarjuk:
np.where(A > A.mean())
A[np.where(A > A.mean())]
a = np.array([[1.0, 2.0], [3.0, 4.0]])
print(a)
a.transpose()
np.linalg.inv(a)
u = np.eye(2)
u
j = np.array([[0.0, -1.0], [1.0, 0.0]])
j @ j # matrix szorzás
np.trace(u) # mátrix nyoma
y = np.array([[5.], [7.]])
x=np.linalg.solve(a, y)
x
a @ x
np.linalg.eig(j)
A Mandelbrot-halmaz azon $c$ komplex számokból áll, melyekre az alábbi $x_{n}$ rekurzív sorozat:
$x_{1}=c$
$x_{n+1}:=(x_{n})^{2}+c$
nem tart végtelenbe, azaz abszolút értékben (hosszára nézve) korlátos.
import matplotlib.pyplot as plt #rajzoláshoz
def mandelbrot( h,w, maxit=20 ):
#y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ]
c=(np.linspace(-1.4,1.4,h))[:, None]*1j + (np.linspace(-2,0.8,w))[None, :]
z = c
divtime = maxit + np.zeros(z.shape, dtype=int)
for i in range(maxit):
z = z**2 - z + c
diverge = z*np.conj(z) > 2**2 # Ki divergál?
div_now = diverge & (divtime==maxit) # Ki divergál ebben a lépésben?
divtime[div_now] = i # felírjuk, hogy mikor divergált
z[diverge] = 2 # ne divárgáljunk túl sokat
return divtime
# a többi a rajzoláshoz kell, most nem fontos
fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(111)
ax.imshow(mandelbrot(1000,1000), interpolation='none')
plt.show()