Algoritmusok Python nyelven

6. Előadás: Numpy

2020. március 12.

Tudományos csomagok (Python Scientific stack)

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

Numpy

A Python Scientific stack (és sok más) alap modulja.

https://numpy.org/

  • lineáris algebra, Fourier transzformáció, random számok,
  • könnyen használható mátrixok, tömbök
  • erősen opitmalizált
  • C/C++/Fortran integráció.
In [223]:
 

Importálási konvenció: import numpy as np

In [291]:
import numpy as np

N-dimenziós tömbök

A numpy központi objektuma az ndarray ($n$-dimenziós tömb).

In [292]:
A = np.array([[1, 2], [3, 4], [5, 6]])     
A
Out[292]:
array([[1, 2],
       [3, 4],
       [5, 6]])
In [293]:
type(A)
Out[293]:
numpy.ndarray

A.shape egy tuple a tömb dimenzióival, alakjával.

In [294]:
A.shape
Out[294]:
(3, 2)

A listákkal ellentétben nem tárolhatunk benne bármit! A dtype megadja a tárolt elemek típusát

In [295]:
A.dtype
Out[295]:
dtype('int32')
In [298]:
a=10**30            #Ez sima ügy
#A[0,0]=10**30      #Ez túl nagy lenne
In [299]:
A = np.array([1.5, 2])
A.dtype
Out[299]:
dtype('float64')

Az elemek elérése

0-tól indexelünk, mint mindig.

Egy sor:

In [300]:
A = np.array([[1, 2], [3, 4], [5, 6]])
A[0], A[1]
Out[300]:
(array([1, 2]), array([3, 4]))

Egy oszlop:

In [301]:
A[:, 0]
Out[301]:
array([1, 3, 5])

egy elem:

In [302]:
A[2, 1], type(A[2, 1])
Out[302]:
(6, numpy.int32)

néhány sor vagy oszlop

In [303]:
A[:2]  # vagy A[:2, :]
Out[303]:
array([[1, 2],
       [3, 4]])
In [304]:
A[:, 1:]
Out[304]:
array([[2],
       [4],
       [6]])
In [305]:
A[::2]
Out[305]:
array([[1, 2],
       [5, 6]])
In [306]:
B = np.array([[[1, 2, 3],[4, 5, 6]]])
B.shape, B.ndim
Out[306]:
((1, 2, 3), 3)
In [307]:
B
Out[307]:
array([[[1, 2, 3],
        [4, 5, 6]]])
In [308]:
B[0].shape
Out[308]:
(2, 3)
In [309]:
B[0, 1], B[0, 1].shape
Out[309]:
(array([4, 5, 6]), (3,))
In [310]:
B[0, 1, 2]
Out[310]:
6

Operációk

Elemenkénti műveletek

Az aritmetikai műveletek itt is használhatóak, elemenként hatnak.

In [311]:
A = np.array([[1, 1], [2, 2]])
P = A >= 2
print(P)
print(P.dtype)
[[False False]
 [ True  True]]
bool
In [312]:
A + A
Out[312]:
array([[2, 2],
       [4, 4]])
In [313]:
A * A
Out[313]:
array([[1, 1],
       [4, 4]])

A leggyakrabban használt matematikai fügvények is elérhetőek és elemenként hatnak.

In [314]:
np.exp(A)
Out[314]:
array([[2.71828183, 2.71828183],
       [7.3890561 , 7.3890561 ]])
In [315]:
np.sin(A*np.pi/6)
Out[315]:
array([[0.5      , 0.5      ],
       [0.8660254, 0.8660254]])
In [316]:
2**A
Out[316]:
array([[2, 2],
       [4, 4]], dtype=int32)
In [317]:
1/A
Out[317]:
array([[1. , 1. ],
       [0.5, 0.5]])
In [318]:
A=np.array([1,1,1,0]) & np.array([1,0,1,1]) 
A
Out[318]:
array([1, 0, 1, 0], dtype=int32)
In [319]:
A=np.array([1,1,1,0]) | np.array([1,0,1,1]) 
A
Out[319]:
array([1, 1, 1, 1], dtype=int32)

Matrix műveletek

A dot a szokásos mátrix szorzás

In [350]:
A = np.array([[1, 2], [3, 4]])
A.dot(A)
Out[350]:
array([[ 7, 10],
       [15, 22]])
In [351]:
A @ A
Out[351]:
array([[ 7, 10],
       [15, 22]])

A belső dimenzióknak passzolniuk kell

In [354]:
B = np.array([[1, 2, 3], [4, 5, 6]])
print(A.shape, B.shape)
A.dot(B)
#B.dot(A)
(2, 2) (2, 3)
Out[354]:
array([[ 9, 12, 15],
       [19, 26, 33]])

Tudunk invertálni, de mint mindig, figyelni kell a kerkítési hibákra.

In [355]:
A_inv = np.linalg.inv(A)
print(A_inv)

A_inv.dot(A)
[[-2.   1. ]
 [ 1.5 -0.5]]
Out[355]:
array([[1.00000000e+00, 0.00000000e+00],
       [1.11022302e-16, 1.00000000e+00]])
In [357]:
np.round(A_inv.dot(A),5)
Out[357]:
array([[1., 0.],
       [0., 1.]])

Nem négyzetes mátrixokra pseudo-inverzet is tuduni számolni.

In [358]:
A = np.array([[1, 2, 3], [4, 5, 6]])
A_pinv = np.linalg.pinv(A)

A.dot(A_pinv).dot(A)
Out[358]:
array([[1., 2., 3.],
       [4., 5., 6.]])

(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.)

In [359]:
M = np.matrix([[1, 2], [3, 4]])
print(np.multiply(M, M))       # elemenként
print(M * M)                   # szokásos mátrix szorzás
[[ 1  4]
 [ 9 16]]
[[ 7 10]
 [15 22]]

Casting

A C nyelv típusai elérhetőek numpy-ban.

In [360]:
P = np.array([[1.2, 1], [1.5, 0]])
print(P.dtype)
P.astype(int)
float64
Out[360]:
array([[1, 1],
       [1, 0]])
In [361]:
(-P.astype(int)).astype("uint32")
Out[361]:
array([[4294967295, 4294967295],
       [4294967295,          0]], dtype=uint32)
In [362]:
np.array([[1, 2], [3, 4]], dtype="float32")
Out[362]:
array([[1., 2.],
       [3., 4.]], dtype=float32)

A stringek számmá konvertálhatóak:

In [363]:
np.float32('-10'), np.float32(-10)
Out[363]:
(-10.0, -10.0)

Megadhatjuk a dtype-ot amikor létrehozzuk a tömböt.

In [364]:
np.array(['10', '20'], dtype="float32")
Out[364]:
array([10., 20.], dtype=float32)

np.datetime64

Időpontok tárolására külön adattípus van.

In [365]:
np.datetime64("2018-03-10")
Out[365]:
numpy.datetime64('2018-03-10')
In [366]:
np.datetime64("2018-03-10") - np.datetime64("2017-12-13")
Out[366]:
numpy.timedelta64(87,'D')

String tömbök

In [368]:
T = np.array(['körte', 'alma'])
print(T)
print(T.shape, T.dtype, type(T))
['körte' 'alma']
(2,) <U5 <class 'numpy.ndarray'>

Fix hosszúságú karakter tömböket tárol!!

In [369]:
T[1] = "banana"
T
Out[369]:
array(['körte', 'banan'], dtype='<U5')

Slicing, bonyolultabb indexelés

A : az adott dimenzión belül mindent vesz.

In [376]:
A = np.array([[1, 2, 3], [4, 5, 6]])
print(A)
print(A[0])
print(A[0, :]) # első sor
print(A[:, 0])  # első oszlop
[[1 2 3]
 [4 5 6]]
[1 2 3]
[1 2 3]
[1 4]

Ezek 1 dimenziós tömbök és nem $1\times n$-es vagy $n\times1$-es tömbök!

In [378]:
A[0, :].shape, A[:, 0].shape
Out[378]:
((3,), (2,))
In [379]:
B = np.array([[[1, 2, 3],[4, 5, 6]]])
B.shape
Out[379]:
(1, 2, 3)
In [381]:
print(B[:, 1, :].shape)
B[:, 1, :]
(1, 3)
Out[381]:
array([[4, 5, 6]])
In [383]:
B[0, 1, :], B[0, 1, :].shape
Out[383]:
(array([4, 5, 6]), (3,))
In [384]:
type(B[0, 1, 1]), B[0, 1, 1]
Out[384]:
(numpy.int32, 5)

Minden eddigi python indexelési trükk működik:

In [385]:
A
Out[385]:
array([[1, 2, 3],
       [4, 5, 6]])
In [386]:
print(A[:, ::-1])
print(A[::-1, :])
print(A[:, ::2])
[[3 2 1]
 [6 5 4]]
[[4 5 6]
 [1 2 3]]
[[1 3]
 [4 6]]

Indexelés listákkal (Advanced indexing)

Egy listával vagy tömbbel fogjuk megadni, hogy hanyadik elemeket szeretnénk.

In [387]:
B = np.array(["a","b","c","d","e","f","g"])
In [388]:
np.array([B[0],B[3],B[4],B[6]])
Out[388]:
array(['a', 'd', 'e', 'g'], dtype='<U1')
In [389]:
B[[0,3,4,6]]            #gyorsabban ugyanaz
Out[389]:
array(['a', 'd', 'e', 'g'], dtype='<U1')
In [390]:
B[np.array([0,3,4,6])]  #tömbbel ugyanaz
Out[390]:
array(['a', 'd', 'e', 'g'], dtype='<U1')

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.

In [391]:
M = np.arange(12).reshape(3,4)
In [392]:
M
Out[392]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In [393]:
np.array([[M[0],M[1]],[M[2],M[2]]])
Out[393]:
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [ 8,  9, 10, 11]]])
In [394]:
M[np.array([[0,1],[2,2]])] #gyorsabban ugyanaz
Out[394]:
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [ 8,  9, 10, 11]]])

Ha több index tömbbel indexelünk, akkor az első az első koordinátnak a második a másodiknak, ... felel meg.

In [395]:
np.array([M[0][2],M[1][2],M[1][0]])
Out[395]:
array([2, 6, 4])
In [396]:
np.array([M[0,2],M[1,2],M[1,0]])
Out[396]:
array([2, 6, 4])
In [400]:
M[np.array([0,1,1]),np.array([2,2,0])] #gyorsabban ugyanaz
Out[400]:
array([2, 6, 4])
In [401]:
np.array([[M[0,1],M[1,0]],[M[2,1],M[2,3]]])
Out[401]:
array([[ 1,  4],
       [ 9, 11]])
In [402]:
M[np.array([[0,1],[2,2]]),np.array([[1,0],[1,3]])]  #gyorsabban ugyanaz
Out[402]:
array([[ 1,  4],
       [ 9, 11]])
In [403]:
M[:,[1,3]]
Out[403]:
array([[ 1,  3],
       [ 5,  7],
       [ 9, 11]])
In [404]:
M[[1,2],:]
Out[404]:
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

Többször is kiválaszthatjuk ugyanazt a sort vagy oszlopot:

In [405]:
M[[2,1,2],:]
Out[405]:
array([[ 8,  9, 10, 11],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

Többdimenzióban még komplikáltabba a helyzet. https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html

A tömb alakjának megváltoztatása

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.

In [406]:
B = np.array([[[1, 2, 3], [4, 5, 6]]])
B.reshape((2, 3))
Out[406]:
array([[1, 2, 3],
       [4, 5, 6]])
In [407]:
B.reshape((3, 2))
Out[407]:
array([[1, 2],
       [3, 4],
       [5, 6]])

ValueError hibát kapunk ha rosz alakot adunk meg.

In [409]:
# B.reshape(7)  # raises ValueError
In [410]:
np.array(range(6)).reshape((1, 2, 3))
Out[410]:
array([[[0, 1, 2],
        [3, 4, 5]]])

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.

In [411]:
X = np.array(range(12)).reshape((2, -1, 2))
print("X.shape:", X.shape)
print(X)
X.shape: (2, 3, 2)
[[[ 0  1]
  [ 2  3]
  [ 4  5]]

 [[ 6  7]
  [ 8  9]
  [10 11]]]

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.

In [413]:
X = np.array([[1, 2], [3, 4]])
X.resize((5, 3))
X.resize((1, 2))
X
Out[413]:
array([[1, 2]])

Viszont a np.resize máshogy működik.

In [414]:
X = np.array([[1, 2], [3, 4]])
np.resize(X, (5, 3))
Out[414]:
array([[1, 2, 3],
       [4, 1, 2],
       [3, 4, 1],
       [2, 3, 4],
       [1, 2, 3]])

Ez nem a tömb metódusa! X nem változik:

In [415]:
X
Out[415]:
array([[1, 2],
       [3, 4]])

Tömbök létrehozása

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 intervallum
  • ones, ones_like, csupa egyes
  • zeros, zeros_like, csupa nulla
  • eye: indetitás mátrix 2 dimenzióban
  • fromfunction függvény alapján

Az np.ones_like() és np.zeros_like() függvények megtartják a formát és a dtype-ot!

In [416]:
np.arange(10), np.arange(10).shape
Out[416]:
(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), (10,))
In [417]:
np.arange(1, 21, 2).reshape(5, -1)
Out[417]:
array([[ 1,  3],
       [ 5,  7],
       [ 9, 11],
       [13, 15],
       [17, 19]])
In [418]:
np.linspace(0, 4, 11)
Out[418]:
array([0. , 0.4, 0.8, 1.2, 1.6, 2. , 2.4, 2.8, 3.2, 3.6, 4. ])
In [419]:
np.ones((3, 2)) * 5
Out[419]:
array([[5., 5.],
       [5., 5.],
       [5., 5.]])
In [421]:
np.zeros((2, 3,2))
Out[421]:
array([[[0., 0.],
        [0., 0.],
        [0., 0.]],

       [[0., 0.],
        [0., 0.],
        [0., 0.]]])
In [422]:
A = np.arange(6).reshape(3, -1)
np.zeros_like(A)
Out[422]:
array([[0, 0],
       [0, 0],
       [0, 0]])
In [424]:
np.eye(5)
Out[424]:
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])
In [425]:
np.eye(4, dtype=bool)
Out[425]:
array([[ True, False, False, False],
       [False,  True, False, False],
       [False, False,  True, False],
       [False, False, False,  True]])

Az egyik leghasznosabb, hogy az indexek függvényében is definiálhatjuk a tömböt:

In [426]:
np.fromfunction(lambda i, j: i == j, (3, 3), dtype=int)
Out[426]:
array([[ True, False, False],
       [False,  True, False],
       [False, False,  True]])
In [427]:
np.fromfunction(lambda i,j: 100*i+j, (5,5))
Out[427]:
array([[  0.,   1.,   2.,   3.,   4.],
       [100., 101., 102., 103., 104.],
       [200., 201., 202., 203., 204.],
       [300., 301., 302., 303., 304.],
       [400., 401., 402., 403., 404.]])

Tömbök összeragasztása

Bármelyik dimenzió szerint ragaszthatunk, ha megfelelőek a dimenziók.

In [428]:
A = np.arange(6).reshape(2, -1)
B = np.arange(8).reshape(2, -1)

np.concatenate((A, B), axis=1)
Out[428]:
array([[0, 1, 2, 0, 1, 2, 3],
       [3, 4, 5, 4, 5, 6, 7]])
In [429]:
np.concatenate((A, B), axis=-1)  # last dimension
Out[429]:
array([[0, 1, 2, 0, 1, 2, 3],
       [3, 4, 5, 4, 5, 6, 7]])
In [431]:
 #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:

In [ ]:
A = np.arange(6).reshape(2, -1)
B = np.arange(8).reshape(2, -1)
In [432]:
np.hstack((A, B))
Out[432]:
array([[0, 1, 2, 0, 1, 2, 3],
       [3, 4, 5, 4, 5, 6, 7]])
In [433]:
A = np.arange(6).reshape(-1, 2)
B = np.arange(8).reshape(-1, 2)
print(A.shape, B.shape)

np.vstack((A, B))
(3, 2) (4, 2)
Out[433]:
array([[0, 1],
       [2, 3],
       [4, 5],
       [0, 1],
       [2, 3],
       [4, 5],
       [6, 7]])
In [434]:
A.T
Out[434]:
array([[0, 2, 4],
       [1, 3, 5]])

np.stack egy új dimenzió szerint egymás mellé rakja a tömböket

In [435]:
A.shape, np.stack((A, A, A, A)).shape
Out[435]:
((3, 2), (4, 3, 2))
In [436]:
np.stack((A, A, A, A))
Out[436]:
array([[[0, 1],
        [2, 3],
        [4, 5]],

       [[0, 1],
        [2, 3],
        [4, 5]],

       [[0, 1],
        [2, 3],
        [4, 5]],

       [[0, 1],
        [2, 3],
        [4, 5]]])

Blokk mátrix készítés:

In [437]:
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)
Out[437]:
array([[1., 1., 0., 0.],
       [1., 1., 0., 0.],
       [0., 0., 1., 1.],
       [0., 0., 1., 1.]])

Iteráció

Alapból az első koordináta szerint van iterálás:

In [438]:
A = np.arange(6).reshape(2, -1)
for row in A:
    print(row)
[0 1 2]
[3 4 5]

De természetesen csinálhatunk ilyet:

In [439]:
B = np.arange(6).reshape(1, 2, 3)

for x in B[0, 0, :]:
    print(x)
0
1
2

És végigiterálhatunk az összes elemen is:

In [440]:
for a in B.flat:
    print(a)
0
1
2
3
4
5
In [441]:
for k in range(B.shape[2]):
    print(B[:, :, k])
[[0 3]]
[[1 4]]
[[2 5]]

Broadcasting

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.

In [442]:
s = 2.0 * np.ones((1, 1))
A=np.arange(12).reshape(3,4)
print(s)
print(A)
s * A
[[2.]]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
Out[442]:
array([[ 0.,  2.,  4.,  6.],
       [ 8., 10., 12., 14.],
       [16., 18., 20., 22.]])

De különböző méretű tömbökön nem tudsz elemenkénti műveletet végrehajtani:

In [444]:
# 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.

In [445]:
np.arange(3).reshape((1,3)) + np.zeros((2, 3))
Out[445]:
array([[0., 1., 2.],
       [0., 1., 2.]])
In [446]:
np.arange(3).reshape((3,1)) + np.zeros((3, 4))
Out[446]:
array([[0., 0., 0., 0.],
       [1., 1., 1., 1.],
       [2., 2., 2., 2.]])

Több dimenzió egyszerre is broadcastolható:

In [447]:
np.arange(3).reshape((1,3,1)) + np.zeros((2,3,5))
Out[447]:
array([[[0., 0., 0., 0., 0.],
        [1., 1., 1., 1., 1.],
        [2., 2., 2., 2., 2.]],

       [[0., 0., 0., 0., 0.],
        [1., 1., 1., 1., 1.],
        [2., 2., 2., 2., 2.]]])

Pontos működés

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.

In [448]:
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))
Nem broadcastolható
Broadcastolható
Broadcastolható
Nem broadcastolható

Meg is mondhatjuk, hogy hol hozzon létre új dimenziókat, a none kulcsszóval.

In [449]:
(np.ones(3)[:, None, None] + np.ones((3,2,2)))
Out[449]:
array([[[2., 2.],
        [2., 2.]],

       [[2., 2.],
        [2., 2.]],

       [[2., 2.],
        [2., 2.]]])

Tehát ekkor így változnak a dimenziók: (3, None, None) + (3, 2, 2) = (3, 2, 2)

Példa

Rács a komplex számsíkon:

In [450]:
np.arange(5)[:, None] + 1j * np.arange(5)[None, :]
Out[450]:
array([[0.+0.j, 0.+1.j, 0.+2.j, 0.+3.j, 0.+4.j],
       [1.+0.j, 1.+1.j, 1.+2.j, 1.+3.j, 1.+4.j],
       [2.+0.j, 2.+1.j, 2.+2.j, 2.+3.j, 2.+4.j],
       [3.+0.j, 3.+1.j, 3.+2.j, 3.+3.j, 3.+4.j],
       [4.+0.j, 4.+1.j, 4.+2.j, 4.+3.j, 4.+4.j]])

Tengely menti aggregálás

Tengely menti szummázás:

In [451]:
Y = np.arange(24).reshape(2,3,4)
Y
Out[451]:
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])
In [452]:
Y.sum()  # összes elem összege
Out[452]:
276
In [453]:
Y.sum(axis=0)
Out[453]:
array([[12, 14, 16, 18],
       [20, 22, 24, 26],
       [28, 30, 32, 34]])
In [454]:
Y.sum(axis=1)
Out[454]:
array([[12, 15, 18, 21],
       [48, 51, 54, 57]])

mean, std, var hasonlóan működik az átlag, szórás és szórásnégyzet kiszámolására.

In [455]:
Y.mean(),Y.std(),Y.var()
Out[455]:
(11.5, 6.922186552431729, 47.916666666666664)
In [456]:
Y.mean(axis=(2, 0))
Out[456]:
array([ 7.5, 11.5, 15.5])

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.

In [457]:
np.random.rand(2, 3).astype("float32")
Out[457]:
array([[0.03818325, 0.8861987 , 0.76502496],
       [0.5051767 , 0.7109141 , 0.05483634]], dtype=float32)

Más eloszlások:

In [458]:
np.random.uniform(1, 2, (2, 2))
Out[458]:
array([[1.64343858, 1.8529117 ],
       [1.2745832 , 1.35914384]])
In [459]:
np.random.standard_normal(10)
Out[459]:
array([ 0.42397157, -0.88312398, -0.85062218,  0.48889929, -0.25736787,
       -0.80380843, -0.85615391,  0.82128132,  1.1553195 , -0.60990312])
In [ ]:
np.random.normal(10, 1, size=(1,10))

Diszkrét eloszlások:

In [463]:
np.random.choice(["A", "2", "3", "4", "5", "6", "7", "8", "9",
                  "10", "J", "Q", "K"], 5, replace=True)
Out[463]:
array(['2', '4', 'J', '4', '4'], dtype='<U2')

choice a valszóínűségeket is megadhatjuk:

In [466]:
np.random.choice(range(1, 7), 10,
                 p=[0.1, 0.1, 0.1, 0.1, 0.1, 0.5])
Out[466]:
array([1, 6, 5, 2, 3, 6, 6, 6, 6, 3])
In [467]:
print(np.random.permutation(["A", "2", "3", "4", "5", "6",
                             "7", "8", "9", "10", "J", "Q", "K"]))
['7' '4' '6' 'Q' '5' '9' 'A' '2' 'J' '10' '8' '3' 'K']

A permutation az első dimenzió szerint permutál.

In [469]:
print(np.random.permutation(np.arange(9).reshape((3, 3))))
[[6 7 8]
 [3 4 5]
 [0 1 2]]

Indexelés Bool értékekkel

Feltételnek megfelelő elemek kiválasztása:

In [470]:
A = np.random.random((4, 3))
print(A.mean())
A
0.5209252334166528
Out[470]:
array([[0.29487358, 0.55808354, 0.83089616],
       [0.77861077, 0.83097402, 0.87254137],
       [0.69566424, 0.39232893, 0.35799782],
       [0.12586243, 0.19439251, 0.31887743]])

Az átlagnál nagyobb elemek:

In [471]:
A[A > A.mean()]
Out[471]:
array([0.55808354, 0.83089616, 0.77861077, 0.83097402, 0.87254137,
       0.69566424])
In [472]:
A > A.mean()
Out[472]:
array([[False,  True,  True],
       [ True,  True,  True],
       [ True, False, False],
       [False, False, False]])

np.where visszatér azokkal a tömbökkel, amik a speckó indexeléshez kellenek, ha a feltételnek megfelelő elemeket akarjuk:

In [473]:
np.where(A > A.mean())
Out[473]:
(array([0, 0, 1, 1, 1, 2], dtype=int64),
 array([1, 2, 0, 1, 2, 0], dtype=int64))
In [474]:
A[np.where(A > A.mean())]
Out[474]:
array([0.55808354, 0.83089616, 0.77861077, 0.83097402, 0.87254137,
       0.69566424])

Lineáris algebra

In [475]:
a = np.array([[1.0, 2.0], [3.0, 4.0]])
In [476]:
print(a)
[[1. 2.]
 [3. 4.]]
In [477]:
a.transpose()
Out[477]:
array([[1., 3.],
       [2., 4.]])
In [478]:
np.linalg.inv(a)
Out[478]:
array([[-2. ,  1. ],
       [ 1.5, -0.5]])
In [479]:
u = np.eye(2) 
u
Out[479]:
array([[1., 0.],
       [0., 1.]])
In [480]:
j = np.array([[0.0, -1.0], [1.0, 0.0]])
In [481]:
j @ j        # matrix szorzás
Out[481]:
array([[-1.,  0.],
       [ 0., -1.]])
In [482]:
np.trace(u)  # mátrix nyoma
Out[482]:
2.0
In [483]:
y = np.array([[5.], [7.]])
x=np.linalg.solve(a, y)
x
Out[483]:
array([[-3.],
       [ 4.]])
In [484]:
a @ x
Out[484]:
array([[5.],
       [7.]])
In [485]:
np.linalg.eig(j)
Out[485]:
(array([0.+1.j, 0.-1.j]),
 array([[0.70710678+0.j        , 0.70710678-0.j        ],
        [0.        -0.70710678j, 0.        +0.70710678j]]))

Mandelbrot halmaz

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.

In [489]:
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()
In [ ]: