Biblioteka numpy¶
import numpy as np
# scipy - jeszcze dużo dodatków
np.__version__
'1.26.2'
tablica = np.array([10, 15, 20])
tablica
array([10, 15, 20])
np.arange(10, 20)
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
np.arange(10, 20, 1.5)
array([10. , 11.5, 13. , 14.5, 16. , 17.5, 19. ])
np.arange(1, 20, 2).sum()
100
# Aby wyliczyć sobie potęgi dwójki:
[2**x for x in range(65)]
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208, 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624, 2251799813685248, 4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 72057594037927936, 144115188075855872, 288230376151711744, 576460752303423488, 1152921504606846976, 2305843009213693952, 4611686018427387904, 9223372036854775808, 18446744073709551616]
Typy numpy¶
numpy definiuje typy liczbowe, które odpowiadają tym używanym przez procesor. Odpowiadają one typom short / int / long / float / double z innych języków programowania (C, Java, C#).
Liczba w nazwie typu to jej rozmiar w bitach (bajt = 8 bitów).
Przykładowo tablica miliarda liczb typu int32
będzie zajmować 4 GB pamięci.
int8
- jakbyte
w Javie lubsigned char
w C, zakres od -128 do +127int16
- jakshort
, zakres od -32768 do +32767int32
- jakint
, zakres od -2_147_483_648 do +2_147_483_647int64
- jaklong
, zakres do 9223372036854775807 (19 cyfr)float16
- liczby zmiennoprzecinkowe o małej precyzji, tylko ok 4-5 cyfr dziesiętnychfloat32
- jakfloat
w C i Javie; średnia precyzja, ok 7-8 cyfrfloat64
- jakdouble
w C i Javie, i jak zwykłyfloat
w Pythonie; duża precyzja, ok 14-15 cyfr
x = np.int32(5)
y = np.int32(1000_000_000)
x, y
(5, 1000000000)
Używając liczb takiego typu ryzykujemy, że wynik nie zmieści się w zakresie. Dla intów 32-bitowych zakresem jest od ok -2mld do ok +2mld i wynik rzędu 5mld nie mieści się w zakresie. Dochodzi do błędu integer overflow.
(dla chętnych - poszukać na YT 'Ariane 5' - efekt integer overflow w praktyce)
x * y
/tmp/ipykernel_22066/4205270810.py:1: RuntimeWarning: overflow encountered in scalar multiply x * y
705032704
x = np.int64(5)
y = np.int64(1000_000_000)
x, y
(5, 1000000000)
x * y
5000000000
a = np.array([100, 110, 120, 130, 140])
b = np.array([1, 2, 3, 4, 5])
a
array([100, 110, 120, 130, 140])
b
array([1, 2, 3, 4, 5])
type(a)
numpy.ndarray
# Można wybierać pojdeyncze elementy
a[2]
120
a[2] * 1000
120000
# Można iterować za pomocą pętli for
for x in a:
print(x)
100 110 120 130 140
# Można operaować na całych tablicach
# Zasadniczo działają wtedy zasady jak dla wektotów / macierzy w matematyce
a + b
array([101, 112, 123, 134, 145])
a * b
array([100, 220, 360, 520, 700])
a / b
array([100. , 55. , 40. , 32.5, 28. ])
a // b
array([100, 55, 40, 32, 28])
b * 10
array([10, 20, 30, 40, 50])
Informacje o tablicach¶
t = np.array([
[10, 11, 12, 13, 14],
[50, 51, 52, 53, 54],
[70, 71, 72, 73, 74],
])
t
array([[10, 11, 12, 13, 14], [50, 51, 52, 53, 54], [70, 71, 72, 73, 74]])
print(t)
[[10 11 12 13 14] [50 51 52 53 54] [70 71 72 73 74]]
# size - ilość wszystkich elementów
t.size
15
# len odczyta (w tym przypadku) ilość wierszy
# generalnie zwraca rozmiar mierzony w najwyższym wymiarze (tym, który w indeksach podaje się najbardziej z lewej)
len(t)
3
# liczba wymiarów - w tym przypadku 2
t.ndim
2
a.ndim
1
# shape - kształt, czyli informacja o rozmiarze w każdym wymiarze
# czyli "macierz 3 × 5"
t.shape
(3, 5)
type(t)
numpy.ndarray
# typ elementu tablicy (data type)
t.dtype
dtype('int64')
# elementami tablic nie muszą być liczby, chociaż tablice napisów i innych obiektów są bardzo rzadko używane
imiona = np.array(['Ala', 'Ola', 'Anna', 'Ela', 'Ula'])
imiona
array(['Ala', 'Ola', 'Anna', 'Ela', 'Ula'], dtype='<U4')
imiona.dtype
dtype('<U4')
# W takiej sytuacji zamieni liczby na stringi
np.array([10, 3.14, 'Ala'])
array(['10', '3.14', 'Ala'], dtype='<U32')
Sposoby tworzenia tablic¶
# array - tworzenie na podstawie listy lub innego źródła
a = np.array([100, 110, 120, 130, 140])
b = np.array([1, 2, 3, 4, 5])
t = np.array([
[10, 11, 12, 13, 14],
[50, 51, 52, 53, 54],
[70, 71, 72, 73, 74],
])
# Jeśli chchemy wymusić użycie określonego typu dla elementów, robimy to parametrem dtype
c = np.array([100, 110, 120, 130, 140], dtype=np.int16)
c
array([100, 110, 120, 130, 140], dtype=int16)
c.dtype
dtype('int16')
# Typ można wskazywać bezpośrednio z biblioteki, ale można też podać tekstowo
d = np.array([1, 2, 3, 4, 5], dtype='float16')
d
array([1., 2., 3., 4., 5.], dtype=float16)
Tworzenie tablic z automatycznie generowaną zawartością¶
# full - tablica wypełniona jednakowymi wartościami
# full(kształt, wartość)
np.full(10, 44)
array([44, 44, 44, 44, 44, 44, 44, 44, 44, 44])
# jeśli ma być wielowymiarowa, to jako kształt należy przekazać tuplę (lub inną sekwencję, np. listę) z wymiarami
np.full((3, 2), 2.5)
array([[2.5, 2.5], [2.5, 2.5], [2.5, 2.5]])
np.full([3, 4, 5], 7, dtype='float32')
array([[[7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.]], [[7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.]], [[7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.], [7., 7., 7., 7., 7.]]], dtype=float32)
# Dedykowane wersje dla zer i jedynek
np.zeros(5)
array([0., 0., 0., 0., 0.])
np.zeros((5, 2), dtype='int32')
array([[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]], dtype=int32)
np.ones(100, dtype='int16')
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int16)
arange
jest czymś analogicznym do range
z Pythona.
Te same zasady (start, stop, step), przy czym w arange można uzywać liczb niecałkowitych.
np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.arange(5, 20)
array([ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
np.arange(5, 25, 3)
array([ 5, 8, 11, 14, 17, 20, 23])
np.arange(5, 10, 0.5)
array([5. , 5.5, 6. , 6.5, 7. , 7.5, 8. , 8.5, 9. , 9.5])
np.arange(2.0, 1.0, -0.1)
array([2. , 1.9, 1.8, 1.7, 1.6, 1.5, 1.4, 1.3, 1.2, 1.1])
Podział przedziału na równe części - linspace Wygeneruj tablicę N liczb między X i Y, rozmieszczając je równomiernie.
Ostatni argument oznacza liczbę generownaych wartości (punktów), a nie liczbę przedziałów.
np.linspace(20, 40, 5)
array([20., 25., 30., 35., 40.])
np.linspace(20, 40, 5, dtype='int32')
array([20, 25, 30, 35, 40], dtype=int32)
# Gdy podamy endpoint=False, to prawy zakres nie jest brany do wynikowej tablicy
# Tutaj 40 jest jakby szótym punktem, który nie jest już uwzględniany w wynikach
np.linspace(20, 40, 5, endpoint=False)
array([20., 24., 28., 32., 36.])
# Praktyczne zastosowanie - podziel równo przedziały, gdy znasz początek i koniec, a nie znasz (i nie chcesz wyliczać) wielkości kroku.
n = 127
maks = 1200
arr = np.linspace(0, maks, n)
arr
array([ 0. , 9.52380952, 19.04761905, 28.57142857, 38.0952381 , 47.61904762, 57.14285714, 66.66666667, 76.19047619, 85.71428571, 95.23809524, 104.76190476, 114.28571429, 123.80952381, 133.33333333, 142.85714286, 152.38095238, 161.9047619 , 171.42857143, 180.95238095, 190.47619048, 200. , 209.52380952, 219.04761905, 228.57142857, 238.0952381 , 247.61904762, 257.14285714, 266.66666667, 276.19047619, 285.71428571, 295.23809524, 304.76190476, 314.28571429, 323.80952381, 333.33333333, 342.85714286, 352.38095238, 361.9047619 , 371.42857143, 380.95238095, 390.47619048, 400. , 409.52380952, 419.04761905, 428.57142857, 438.0952381 , 447.61904762, 457.14285714, 466.66666667, 476.19047619, 485.71428571, 495.23809524, 504.76190476, 514.28571429, 523.80952381, 533.33333333, 542.85714286, 552.38095238, 561.9047619 , 571.42857143, 580.95238095, 590.47619048, 600. , 609.52380952, 619.04761905, 628.57142857, 638.0952381 , 647.61904762, 657.14285714, 666.66666667, 676.19047619, 685.71428571, 695.23809524, 704.76190476, 714.28571429, 723.80952381, 733.33333333, 742.85714286, 752.38095238, 761.9047619 , 771.42857143, 780.95238095, 790.47619048, 800. , 809.52380952, 819.04761905, 828.57142857, 838.0952381 , 847.61904762, 857.14285714, 866.66666667, 876.19047619, 885.71428571, 895.23809524, 904.76190476, 914.28571429, 923.80952381, 933.33333333, 942.85714286, 952.38095238, 961.9047619 , 971.42857143, 980.95238095, 990.47619048, 1000. , 1009.52380952, 1019.04761905, 1028.57142857, 1038.0952381 , 1047.61904762, 1057.14285714, 1066.66666667, 1076.19047619, 1085.71428571, 1095.23809524, 1104.76190476, 1114.28571429, 1123.80952381, 1133.33333333, 1142.85714286, 1152.38095238, 1161.9047619 , 1171.42857143, 1180.95238095, 1190.47619048, 1200. ])
# Teraz różnice pomiędzy kolejnymi punktami powinny być jednakowe.
arr[3] - arr[2]
9.523809523809522
arr[10] - arr[9]
9.523809523809533
# logspace - liczby rozłożone równomiernie w przestrzeni logarytmicznej.
# Czyli proporcje (ilorazy) między kolejnymi elementami są jednakowe.
# Pierwszy i drugi argument to są wykładniki, domyślną podstawą jest 10,
# czyli tu generuję liczby od 10**0 do 10**7
np.logspace(0, 7, 8, dtype='int64')
array([ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000])
np.logspace(4, 20, 17, base=2, dtype='int64')
array([ 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576])
# Gdybyśmy wiedzieli, że początkiem przedziału jest 100, a końcem 1500 i chcieli podzielić to 4 równe przedziały (czyli 5 punktów) w skali logarytmicznej,
# to np tak:
x = 100.0
y = 1500.0
dane = np.logspace(np.log10(x), np.log10(y), 5)
dane
array([ 100. , 196.79896713, 387.29833462, 762.19912223, 1500. ])
# Teraz proporcje między kolejnymi elementami są jednakowe
dane[1] / dane[0]
1.9679896712654306
dane[2] / dane[1]
1.9679896712654306
a
array([100, 110, 120, 130, 140])
np.diag(a)
array([[100, 0, 0, 0, 0], [ 0, 110, 0, 0, 0], [ 0, 0, 120, 0, 0], [ 0, 0, 0, 130, 0], [ 0, 0, 0, 0, 140]])
macierz_identycznosciowa = np.diag(np.ones(10))
macierz_identycznosciowa
array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
# Ale na to jest prostszy sposób
np.eye(7)
array([[1., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 1., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 0., 1.]])
# Z tym, że tutaj można podać nietypowe wymiary - i gdy to nie będzie kwadrat, to już nie będzie to macierz ident.
np.eye(10, 5)
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.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]])
np.eye(10, dtype='int32')
array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], dtype=int32)
# Wreszcie, konkretnie dla macierzy identycznościowej jej dedykowana funkcja.
np.identity(10)
array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
np.identity(5, dtype='int16')
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]], dtype=int16)
reshape¶
Tworzy nową tablicę z takimi samymi elementami, ale rozmieszczonymi w innym kształcie.
Wymary muszą być tak dobrane, aby liczba elementów się zgadzała; inaczej będzie błąd.
c = np.arange(24)
c
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])
d = c.reshape(4, 6)
d
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]])
c.shape
(24,)
d.shape
(4, 6)
c.reshape(4, 3, 2)
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]]])
#ERR c.reshape(5, 5)
# Jako jeden z wymiarów można podać -1 i wtedy zostanie on dobrany automatycznie.
c.reshape(3, -1)
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]])
#ERR c.reshape(5, -1)
c.reshape(-1, 4)
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]])
c.reshape(4, -1, 3)
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]]])
d
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]])
d.reshape(3, -1)
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]])
Funkcje losujące w numpy¶
Kolejnym sposobem generowania tablic, jest tworzenie tablic z (pesudo)losowymi wartościami.
O ile w innych sytuacjach w programowaniu często losuje się pojedyncze liczby, to w numpy zazwyczaj pobieramy od razu całe tablice. W tej sytuacji szczególnie dobrze widać jaki jest rozkład pobranych wartości.
np.random.rand(100)
array([3.31453055e-01, 8.24259722e-01, 2.84469468e-01, 9.86221550e-01, 5.47865941e-01, 4.13916466e-01, 7.04353055e-01, 8.34806951e-01, 4.86295852e-01, 2.23872612e-01, 3.90999229e-01, 3.90934657e-01, 3.65957436e-01, 9.08766202e-01, 7.63272850e-01, 3.25544227e-01, 8.31738885e-01, 1.47934369e-01, 2.50951681e-01, 7.71858950e-01, 1.24314380e-01, 4.17359850e-01, 3.19560772e-01, 9.87871625e-01, 8.26386055e-01, 1.10428746e-01, 3.67436231e-01, 6.37947354e-01, 5.53297819e-01, 4.95815980e-01, 2.22976582e-01, 9.24756933e-01, 7.30663891e-01, 3.87698708e-01, 8.49520272e-01, 5.53153146e-01, 3.36838851e-01, 8.17695998e-01, 6.00914159e-01, 6.25865187e-01, 3.60821285e-01, 3.06951483e-01, 7.05864240e-01, 7.29799061e-02, 9.87776240e-02, 6.34720614e-04, 1.02279020e-01, 6.61337514e-04, 7.27813279e-01, 8.42359704e-01, 9.86165351e-01, 3.23198045e-01, 4.55718561e-01, 7.39777126e-01, 7.17044654e-01, 9.73983557e-01, 2.00385705e-01, 9.27574301e-01, 3.68896021e-01, 8.45257042e-01, 8.08767077e-01, 1.38596360e-01, 3.21125041e-01, 2.88418250e-01, 4.60653716e-01, 8.09173841e-01, 9.36020750e-01, 3.39259026e-01, 6.44673787e-03, 8.30777393e-02, 3.56994285e-01, 4.22344623e-01, 2.70245866e-01, 9.68793420e-01, 4.13488822e-01, 8.12963482e-01, 8.87157082e-01, 9.18304746e-01, 1.42467560e-02, 6.00450932e-01, 4.67951510e-01, 8.23261599e-01, 3.09395538e-01, 6.61861442e-01, 3.35802028e-02, 5.41616701e-01, 4.53689404e-01, 8.94697546e-01, 3.15462382e-01, 1.62058578e-01, 9.47238434e-01, 5.93645270e-01, 3.24289977e-01, 5.20944279e-01, 7.86686487e-01, 5.12723192e-01, 2.37338358e-02, 7.17543561e-01, 4.85529644e-01, 1.21258614e-01])
Generator liczb pseudolosowych deterministycznie zwraca kolejne liczby z pewnego ciągu, który „na oko” ma dobry rozkład. Aby w różnych uruchomieniach pojawiały się różne wartości, jest o inicjalizowany bieżącym odczytem zegara.
Jeśli chcemy, aby notatnik uruchamiany wielokrotnie lub na różnych komputerach przez różne osoby zawierał te same liczby pseudolosowe, możemy zainicjalizować generator wybraną konkretną liczbą. Robi się to za pomocą funkcji seed
.
np.random.seed(100)
# Liczby float z zakresu od 0 do 1, rozkład jednostajny.
np.random.rand(10)
array([0.54340494, 0.27836939, 0.42451759, 0.84477613, 0.00471886, 0.12156912, 0.67074908, 0.82585276, 0.13670659, 0.57509333])
# Generowanie liczb całkowitych, tutaj liczby z zakresu [100, 200)
np.random.randint(100, 200, 10)
array([160, 158, 116, 109, 193, 186, 102, 127, 104, 131])
jednostajny = np.random.rand(1000)
import matplotlib.pyplot as plt
%matplotlib inline
plt.hist(jednostajny, bins=10)
(array([103., 99., 103., 97., 99., 116., 91., 98., 91., 103.]), array([4.86759475e-04, 1.00385999e-01, 2.00285238e-01, 3.00184477e-01, 4.00083716e-01, 4.99982955e-01, 5.99882194e-01, 6.99781434e-01, 7.99680673e-01, 8.99579912e-01, 9.99479151e-01]), <BarContainer object of 10 artists>)
# Rozkład normalny („Gaussowski”)
normalny = np.random.randn(1000)
plt.hist(normalny, bins=10)
(array([ 1., 3., 6., 61., 184., 257., 254., 147., 65., 22.]), array([-4.24242115, -3.54206947, -2.84171779, -2.14136612, -1.44101444, -0.74066276, -0.04031108, 0.6600406 , 1.36039228, 2.06074396, 2.76109563]), <BarContainer object of 10 artists>)
plt.hist(np.random.randn(10000)*25 + 50, bins=100)
plt.show()
Operacje na tablicach¶
a = np.arange(10, 20)
b = np.arange(10, 0, -1)
t = np.arange(40).reshape(5, 8)
v = np.arange(50, 90).reshape(5, 8)
w = v.T
a
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
b
array([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
t
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], [24, 25, 26, 27, 28, 29, 30, 31], [32, 33, 34, 35, 36, 37, 38, 39]])
v
array([[50, 51, 52, 53, 54, 55, 56, 57], [58, 59, 60, 61, 62, 63, 64, 65], [66, 67, 68, 69, 70, 71, 72, 73], [74, 75, 76, 77, 78, 79, 80, 81], [82, 83, 84, 85, 86, 87, 88, 89]])
w
array([[50, 58, 66, 74, 82], [51, 59, 67, 75, 83], [52, 60, 68, 76, 84], [53, 61, 69, 77, 85], [54, 62, 70, 78, 86], [55, 63, 71, 79, 87], [56, 64, 72, 80, 88], [57, 65, 73, 81, 89]])
Generalnie można stosować operacje arytmetyczne między tablicami. Jeśli wymiary tablic się zgadzają, operacje są wykonywane „per element”, na zgodnych pozycjach.
a + b
array([20, 20, 20, 20, 20, 20, 20, 20, 20, 20])
a - b
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
a * b
array([100, 99, 96, 91, 84, 75, 64, 51, 36, 19])
a / b
array([ 1. , 1.22222222, 1.5 , 1.85714286, 2.33333333, 3. , 4. , 5.66666667, 9. , 19. ])
a // b
array([ 1, 1, 1, 1, 2, 3, 4, 5, 9, 19])
a % b
array([0, 2, 4, 6, 2, 0, 0, 2, 0, 0])
t + v
array([[ 50, 52, 54, 56, 58, 60, 62, 64], [ 66, 68, 70, 72, 74, 76, 78, 80], [ 82, 84, 86, 88, 90, 92, 94, 96], [ 98, 100, 102, 104, 106, 108, 110, 112], [114, 116, 118, 120, 122, 124, 126, 128]])
t * v
array([[ 0, 51, 104, 159, 216, 275, 336, 399], [ 464, 531, 600, 671, 744, 819, 896, 975], [1056, 1139, 1224, 1311, 1400, 1491, 1584, 1679], [1776, 1875, 1976, 2079, 2184, 2291, 2400, 2511], [2624, 2739, 2856, 2975, 3096, 3219, 3344, 3471]])
Mnożenie macierzy oznaczane jest symbolem @
i wymaga użycia tablic pasujących wielkością.
v @ w
array([[22940, 26364, 29788, 33212, 36636], [26364, 30300, 34236, 38172, 42108], [29788, 34236, 38684, 43132, 47580], [33212, 38172, 43132, 48092, 53052], [36636, 42108, 47580, 53052, 58524]])
w @ v
array([[22420, 22750, 23080, 23410, 23740, 24070, 24400, 24730], [22750, 23085, 23420, 23755, 24090, 24425, 24760, 25095], [23080, 23420, 23760, 24100, 24440, 24780, 25120, 25460], [23410, 23755, 24100, 24445, 24790, 25135, 25480, 25825], [23740, 24090, 24440, 24790, 25140, 25490, 25840, 26190], [24070, 24425, 24780, 25135, 25490, 25845, 26200, 26555], [24400, 24760, 25120, 25480, 25840, 26200, 26560, 26920], [24730, 25095, 25460, 25825, 26190, 26555, 26920, 27285]])
Jeśli rozmiary tablic się nie zgadzają (np. krótsza i dłuższa jednowymiarowa tablica), powoduje to błąd.
# ValueError
# np.array([1, 2, 3]) * np.array([11, 12, 13, 14])
# ValueError
# t + w
Broadcasting¶
Jeśli jednak argumenty mają różną liczbę wymiarów, numpy podejmuje próbę przeprowadzenia operacji broadcasting, która polega na powieleniu danych, aby uzupełnić brakujący wymiar.
Najlepszym przykładem jest powielenie jednego wiersza, aby uzyskać tyle wierszy, ile posiada druga tablica.
g = np.array([1, 2, 3, 4, 5])
h = np.array([
[10, 20, 30, 40, 50],
[100, 200, 300, 400, 500],
[1000, 2000, 3000, 4000, 5000],
])
g + h
array([[ 11, 22, 33, 44, 55], [ 101, 202, 303, 404, 505], [1001, 2002, 3003, 4004, 5005]])
Ale działa to w różne strony, nawet w kilka jednocześnie:
g = np.array([[1],
[2],
[3]])
h = np.array([
[10, 20, 30, 40, 50],
[100, 200, 300, 400, 500],
[1000, 2000, 3000, 4000, 5000],
])
g + h
array([[ 11, 21, 31, 41, 51], [ 102, 202, 302, 402, 502], [1003, 2003, 3003, 4003, 5003]])
g = np.array([1, 2, 3, 4, 5])
h = np.array([[100],
[200],
[300]])
g + h
array([[101, 102, 103, 104, 105], [201, 202, 203, 204, 205], [301, 302, 303, 304, 305]])
%pprint
Pretty printing has been turned OFF
d3 = np.random.rand(5*10*3).reshape(5, 10, 3) * 100.0
d3
array([[[20.77468354, 52.59137503, 97.48647409], [62.42582292, 17.12401438, 10.09106112], [82.90940154, 96.67908726, 93.55647434], [57.12906566, 65.30888178, 33.12558963], [97.06466058, 4.44342006, 37.77203671], [85.8368438 , 38.61150895, 47.53379762], [ 9.78858587, 2.98857293, 50.67247657], [98.66142583, 46.91103274, 36.17638063], [ 7.95545013, 72.22736441, 85.03220205], [ 2.01537568, 24.57806507, 24.60706984]], [[60.26382953, 39.21532521, 69.45802257], [64.91502955, 22.90854365, 63.33072236], [62.17703359, 89.57509609, 72.36648606], [47.24628802, 75.45986122, 71.42303184], [74.88592042, 84.24075714, 43.08310947], [89.73476707, 29.78942389, 8.13245342], [58.9916479 , 57.5727015 , 53.74846818], [ 8.52789782, 27.45866237, 85.40632302], [80.4840114 , 3.72941453, 33.67676857], [30.60508003, 65.10202971, 15.0767815 ]], [[22.91796387, 33.66468471, 11.58284787], [82.70486494, 25.58862713, 8.85710901], [96.05458196, 22.27216592, 86.88676278], [40.6976419 , 35.09643016, 64.19349516], [15.06812199, 37.3072805 , 78.44813408], [54.41629057, 87.58040307, 84.97357785], [ 9.88116531, 29.22518685, 35.96513353], [10.03072168, 58.01284743, 81.57909284], [40.38913993, 79.17767712, 46.06589119], [81.42298256, 43.49854046, 16.65471239]], [[ 7.74014755, 62.04422949, 60.73016565], [25.61369746, 99.45251398, 13.43522669], [34.36105221, 41.31203172, 12.54333236], [48.54043717, 77.55004905, 8.4928454 ], [17.09838706, 30.28284352, 48.27583824], [ 6.20668772, 79.71543193, 87.13417147], [ 7.12655683, 88.55698287, 15.00428966], [29.76900956, 6.70504356, 71.84614958], [ 7.22440379, 10.62873949, 33.1026422 ], [24.68642182, 24.83172962, 86.29812893]], [[73.92148741, 93.42716828, 45.54270843], [21.79758124, 67.65624339, 39.48641364], [79.33790855, 54.26892985, 45.31459653], [99.93228467, 59.80322076, 29.95309268], [43.03292894, 32.50722983, 82.15139342], [91.38581803, 12.12643529, 77.38812407], [60.57227984, 0.41180725, 5.72317641], [45.951643 , 73.32741302, 64.59881914], [69.59889213, 41.58058327, 74.45956073], [90.87358269, 30.48219785, 46.80896599]]])
d3 *= np.array([0.5, 0, 1])
d3
array([[[10.38734177, 0. , 97.48647409], [31.21291146, 0. , 10.09106112], [41.45470077, 0. , 93.55647434], [28.56453283, 0. , 33.12558963], [48.53233029, 0. , 37.77203671], [42.9184219 , 0. , 47.53379762], [ 4.89429294, 0. , 50.67247657], [49.33071291, 0. , 36.17638063], [ 3.97772506, 0. , 85.03220205], [ 1.00768784, 0. , 24.60706984]], [[30.13191476, 0. , 69.45802257], [32.45751477, 0. , 63.33072236], [31.0885168 , 0. , 72.36648606], [23.62314401, 0. , 71.42303184], [37.44296021, 0. , 43.08310947], [44.86738354, 0. , 8.13245342], [29.49582395, 0. , 53.74846818], [ 4.26394891, 0. , 85.40632302], [40.2420057 , 0. , 33.67676857], [15.30254001, 0. , 15.0767815 ]], [[11.45898193, 0. , 11.58284787], [41.35243247, 0. , 8.85710901], [48.02729098, 0. , 86.88676278], [20.34882095, 0. , 64.19349516], [ 7.53406099, 0. , 78.44813408], [27.20814529, 0. , 84.97357785], [ 4.94058266, 0. , 35.96513353], [ 5.01536084, 0. , 81.57909284], [20.19456996, 0. , 46.06589119], [40.71149128, 0. , 16.65471239]], [[ 3.87007377, 0. , 60.73016565], [12.80684873, 0. , 13.43522669], [17.18052611, 0. , 12.54333236], [24.27021858, 0. , 8.4928454 ], [ 8.54919353, 0. , 48.27583824], [ 3.10334386, 0. , 87.13417147], [ 3.56327841, 0. , 15.00428966], [14.88450478, 0. , 71.84614958], [ 3.61220189, 0. , 33.1026422 ], [12.34321091, 0. , 86.29812893]], [[36.9607437 , 0. , 45.54270843], [10.89879062, 0. , 39.48641364], [39.66895428, 0. , 45.31459653], [49.96614234, 0. , 29.95309268], [21.51646447, 0. , 82.15139342], [45.69290901, 0. , 77.38812407], [30.28613992, 0. , 5.72317641], [22.9758215 , 0. , 64.59881914], [34.79944606, 0. , 74.45956073], [45.43679134, 0. , 46.80896599]]])
Szczególnym przypadkiem broadcastingu tak naprawdę jest operacja arytmetyczna łącząca tablicę i wartość skalarną: wartość skalarna jest „rozmnażana” tyle razy, iel trzeba, aby dopasować ją do tablicy.
a + 1000
array([1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019])
t * (-1)
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], [-24, -25, -26, -27, -28, -29, -30, -31], [-32, -33, -34, -35, -36, -37, -38, -39]])
Wybieranie elementów i zakresów¶
Indeksy i wycinanki (slices), podobnie jak dla list, ale tutaj może to być wielowymiarowe.
a = np.arange(10, 20)
a
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
t = np.arange(50).reshape(5, 10)
t
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, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])
t.shape
(5, 10)
# Dla jednowymiarowej tablicy jest tak jak dla listy
a[5]
15
a[2:7]
array([12, 13, 14, 15, 16])
a[2:7:2]
array([12, 14, 16])
# Można pomijać współrzędne - wtedy przyjmowane są:
# - początek 0
# - koniec size
# - krok 1
# od 3 do końca
a[3:]
array([13, 14, 15, 16, 17, 18, 19])
# od początku do 7 (wyłączając)
a[:7]
array([10, 11, 12, 13, 14, 15, 16])
a[3::]
array([13, 14, 15, 16, 17, 18, 19])
a[:7:]
array([10, 11, 12, 13, 14, 15, 16])
a[::-1]
array([19, 18, 17, 16, 15, 14, 13, 12, 11, 10])
# Gdy tablica jest wielowymiarowa, to podanie współrzędnych w jednym wymiarze wybiera np. pojedynczy wiersz
t[2]
array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
t[2:4]
array([[20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39]])
# Aby wskazać konkretny element, używa się indeksowania wielopoziomowego, gdzie współrzędne rozdziela się przecinkiem
# wiersz nr 2, kolumna nr 4 (przy czym numeracja jest od zera)
t[2,4]
24
i = 1
j = 6
t[i, j]
16
# Może to nie jest typowe dla numpy, ale zobaczmy, że można iterować za pomocą pętli
# Styl języka C:
for i in range(len(t)):
for j in range((len(t[i]))):
print(t[i,j], end=' ')
print()
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
# Tworze kopię tej tablicy, aby w niej coś mzienić, a nie psuć oryginału
tab = t.copy()
tab
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, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])
# Tablice numpy są mutowalne. Zmiana wygląda podonie jak zmiana wartości w liście:
a[1] = 91
a
array([10, 91, 12, 13, 14, 15, 16, 17, 18, 19])
tab[1,3] = 777
tab
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [ 10, 11, 12, 777, 14, 15, 16, 17, 18, 19], [ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])
# Takiej pętli można użyć, aby indywidualnie zmieniać wartości poszczególnych pól.
# Np. tutaj do liczby dodam numer kolumny
for i in range(len(tab)):
for j in range((len(tab[i]))):
tab[i,j] += j
tab
array([[ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18], [ 10, 12, 14, 780, 18, 20, 22, 24, 26, 28], [ 20, 22, 24, 26, 28, 30, 32, 34, 36, 38], [ 30, 32, 34, 36, 38, 40, 42, 44, 46, 48], [ 40, 42, 44, 46, 48, 50, 52, 54, 56, 58]])
# Jeśli chcemy w pętli tylko odczytać elementy, to można prościej:
for wiersz in tab:
for element in wiersz:
print(element, end='; ')
print()
0; 2; 4; 6; 8; 10; 12; 14; 16; 18; 10; 12; 14; 780; 18; 20; 22; 24; 26; 28; 20; 22; 24; 26; 28; 30; 32; 34; 36; 38; 30; 32; 34; 36; 38; 40; 42; 44; 46; 48; 40; 42; 44; 46; 48; 50; 52; 54; 56; 58;
# Wracając do indeksów
t
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, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])
t[2,4]
24
# Gdy w przypadku wielowymiarowym podajemy zakresy, to w wyniku dostajemy fragment tablicy
t[1:3, 5:8]
array([[15, 16, 17], [25, 26, 27]])
Dzięki zostawianiu przedziałów otwartych, łatwo wyciąć dane tylko w jednym wymiarze
# Wybrane wiersze i wszystkie kolumny
t[1:3, :]
array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]])
# To można było uzyskać także w ten sposób
t[1:3]
array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]])
# Wszystkie wiersze i wybrane kolumny
t[:, 5:8]
array([[ 5, 6, 7], [15, 16, 17], [25, 26, 27], [35, 36, 37], [45, 46, 47]])
d = np.arange(60).reshape(3, 4, 5)
d
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, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39]], [[40, 41, 42, 43, 44], [45, 46, 47, 48, 49], [50, 51, 52, 53, 54], [55, 56, 57, 58, 59]]])
d[1, 0, 3]
23
d[1, :, 3]
array([23, 28, 33, 38])
d[1, :, :]
array([[20, 21, 22, 23, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39]])
# Jeśli we wszystkich pozostałych wymiarach stosuję wildcard "weź wszystko", to można jeszcze krócej:
d[1, ...]
array([[20, 21, 22, 23, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39]])
d[..., 3]
array([[ 3, 8, 13, 18], [23, 28, 33, 38], [43, 48, 53, 58]])
t
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, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])
# Aby odczytać macierz transponowaną (zamiana znaczenia wierszy z kolumnami), możemy użyć specjalnego trybutu .T
t.T
array([[ 0, 10, 20, 30, 40], [ 1, 11, 21, 31, 41], [ 2, 12, 22, 32, 42], [ 3, 13, 23, 33, 43], [ 4, 14, 24, 34, 44], [ 5, 15, 25, 35, 45], [ 6, 16, 26, 36, 46], [ 7, 17, 27, 37, 47], [ 8, 18, 28, 38, 48], [ 9, 19, 29, 39, 49]])
# reshape robi coś innego
t.reshape(10, 5)
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, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39], [40, 41, 42, 43, 44], [45, 46, 47, 48, 49]])
Warunki i filtrowanie¶
np.random.seed(0)
a = np.random.randint(-5, 10, 20)
a
array([ 7, 0, -5, -2, 6, -2, 2, 4, -2, 0, -3, -1, 2, 1, 3, 3, 7, 5, -4, 1])
b = [10, 11, 12, 13, 14]
# Co się stanie, gdy porównamy tablicę z liczbą.
# Powstaje tablica wartości logicznych. Na danej pozycji jest info czy element spełniał warunek
a > 0
array([ True, False, False, False, True, False, True, True, False, False, False, False, True, True, True, True, True, True, False, True])
Z kolei operacja indeksowania pozwala przekazać matrycę wartości True/False decydującą, które elementy zostaną zwrócone w wyniku
# Jeśli wynik porównania zapiszemy sobie do zmiennej:
maska = a > 0
# wygląda to tak:
maska
array([ True, False, False, False, True, False, True, True, False, False, False, False, True, True, True, True, True, True, False, True])
# To teraz mogę wybrać elementy z tablicy a, dla których w masce jest True
a[maska]
array([7, 6, 2, 4, 2, 1, 3, 3, 7, 5, 1])
# W praktyce zapisuje się to bezpośrednio i wygląda to bardzo przejrzyście:
a[a>0]
# Wybierz z tablicy a takie elementy, które są dodatnie
array([7, 6, 2, 4, 2, 1, 3, 3, 7, 5, 1])
Aby połączyć kilka warunków, możemy użyć spójników logicznych, ale tym razem nie pisanych jako and or, tylko za pomocą znaczków & |
Bo technicznie wykonujemy tutaj operacje na bitach w tych maskach opisujących gdzie była pracwa, a gdzie fałsz.
a[(a >= 0) & (a < 5)]
array([0, 2, 4, 0, 2, 1, 3, 3, 1])
# Jak to działa
maska1 = a >= 0
maska1
array([ True, True, False, False, True, False, True, True, False, True, False, False, True, True, True, True, True, True, False, True])
maska2 = a < 5
maska2
array([False, True, True, True, False, True, True, True, True, True, True, True, True, True, True, True, False, False, True, True])
maska1 & maska2
array([False, True, False, False, False, False, True, True, False, True, False, False, True, True, True, True, False, False, False, True])
# Inny przykład: wybierzmy liczby dodatnie, które jednocześnie są parzyste
a[(a > 0) & (a % 2 == 0)]
array([6, 2, 4, 2])
# Lub to jest |
a[(a > 0) | (a % 2 == 0)]
array([ 7, 0, -2, 6, -2, 2, 4, -2, 0, 2, 1, 3, 3, 7, 5, -4, 1])
# Negacja jako ~
a[~maska]
array([ 0, -5, -2, -2, -2, 0, -3, -1, -4])
# where zwraca info o pozycjach, na których warunek jest prawdziwy
np.where(a % 2 == 0)
(array([ 1, 3, 4, 5, 6, 7, 8, 9, 12, 18]),)
min(a), max(a)
(-5, 7)
# Czy jakikolwiek element spełnia warunek
(a > 6).any()
True
(a > 8).any()
False
# Czy wszystkie elementy spełniają warunek
(a > 0).all()
False
Funkcje agregujące¶
Zasadniczo funkcje agregujace zwracają pojedynczy wynik na podstawie całej tabeli.
t
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, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])
# Większosć funkcji agregujących jest dostępna jako metody w obiektach array:
t.sum()
1225
# Nietypowa nazwa: średnia to jest mean a nie avg
t.mean()
24.5
t.std()
14.430869689661812
t.size, t.sum(), t.mean(), t.min(), t.max(), t.std()
(50, 1225, 24.5, 0, 49, 14.430869689661812)
# Mediana jest dostępna jako funkcja w bibliotece numpy, a nie metoda obiektu
np.median(t)
24.5
# W przypadku tablic wielowymiarowych można też agregować dane "wierszami" albo "kolumnami":
t.sum()
1225
# średnia z każdej kolumny
t.sum(axis=0)
array([100, 105, 110, 115, 120, 125, 130, 135, 140, 145])
# średnia z każdego wiersza
t.sum(axis=1)
array([ 45, 145, 245, 345, 445])
# w parametrze axis podaje się numer tego wymiaru, który znika, który jest redukowany, wzdłuż którego wyliczane są agregaty
t.mean(axis=1).reshape(-1, 1)
array([[ 4.5], [14.5], [24.5], [34.5], [44.5]])
Rozwiązywanie układów równań liniowych¶
Powiedzmy, że mamy układ równań: 2x + y = 5 3x - y = 5
a = np.array([[2, 1],
[3, -1]])
b = np.array([5, 5])
np.linalg.solve(a, b)
array([2., 1.])
# Przykład sprytnego odczytu wyników dzięki technice rozpakowywania:
x, y = np.linalg.solve(a, b)
print(f'Rozwiązania równania: x = {x}, y = {y}')
Rozwiązania równania: x = 2.0, y = 1.0000000000000002
Wczytywanie danych z pliku¶
Dosyć łatwo wczytuje się dane tabelaryczne z plików tekstowych o formacie przypominającym CSV: wartości rozdzielone separatorem. Służy do tego funkcja genfromtxt
.
Przy domyślnych ustawieniach wczytywana jest dwuwymiarowa tablica float64
, za separator uznawane są dowolne ciągi białych znaków.
liczby = np.genfromtxt('pliki/liczby.txt')
liczby
array([[10. , 11. , 12. , 13. , 14. , 15. , 16. , 17. , 18. , 19. ], [10. , 9. , 8. , 7. , 6. , 5. , 4. , 3. , 2. , 1. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 1.1 , 1.25, 1.44, 1.75, 2. , 1.66, 1.5 , 1.33, 1.2 , 1. ], [ 5. , 4. , 6. , 3. , 7. , 2. , 8. , 1. , 9. , 0. ]])
liczby.dtype, liczby.shape
(dtype('float64'), (5, 10))
liczby *= 5
liczby -= 1.5
liczby
array([[48.5 , 53.5 , 58.5 , 63.5 , 68.5 , 73.5 , 78.5 , 83.5 , 88.5 , 93.5 ], [48.5 , 43.5 , 38.5 , 33.5 , 28.5 , 23.5 , 18.5 , 13.5 , 8.5 , 3.5 ], [-1.5 , -1.5 , -1.5 , -1.5 , -1.5 , -1.5 , -1.5 , -1.5 , -1.5 , -1.5 ], [ 4. , 4.75, 5.7 , 7.25, 8.5 , 6.8 , 6. , 5.15, 4.5 , 3.5 ], [23.5 , 18.5 , 28.5 , 13.5 , 33.5 , 8.5 , 38.5 , 3.5 , 43.5 , -1.5 ]])
Aby zapisać tablicę do pliku, można użyć savetxt
:
np.savetxt('zmienione_liczby.txt', liczby)
# Sprawdź - plik został zapisany na dysku
Obie funkcje posiadają liczne parametry, które pozwalają dostosować się do formatu oraz wybrać zakres danych.
Do najważniejszych opcji genfromtxt
należą:
delimiter
– znak będący separatorem pól, często przecinek lub średnikusecols
– w formie listy liczb można podać numery tych kolumn, które mają być wczytane; pozostałe zostaną pominięte, dzięki czemu można na przykład ominąć kolumny tekstoweskiprows
– ilość wierszy, które mają być pominięte na początku, np. wiersz nagłówkowydtype
– typ elementów
kwiatki = np.genfromtxt('pliki/iris.data', delimiter=',', usecols=[0,1,2,3])
kwiatki.shape
(150, 4)
kwiatki
array([[5.1, 3.5, 1.4, 0.2], [4.9, 3. , 1.4, 0.2], [4.7, 3.2, 1.3, 0.2], [4.6, 3.1, 1.5, 0.2], [5. , 3.6, 1.4, 0.2], [5.4, 3.9, 1.7, 0.4], [4.6, 3.4, 1.4, 0.3], [5. , 3.4, 1.5, 0.2], [4.4, 2.9, 1.4, 0.2], [4.9, 3.1, 1.5, 0.1], [5.4, 3.7, 1.5, 0.2], [4.8, 3.4, 1.6, 0.2], [4.8, 3. , 1.4, 0.1], [4.3, 3. , 1.1, 0.1], [5.8, 4. , 1.2, 0.2], [5.7, 4.4, 1.5, 0.4], [5.4, 3.9, 1.3, 0.4], [5.1, 3.5, 1.4, 0.3], [5.7, 3.8, 1.7, 0.3], [5.1, 3.8, 1.5, 0.3], [5.4, 3.4, 1.7, 0.2], [5.1, 3.7, 1.5, 0.4], [4.6, 3.6, 1. , 0.2], [5.1, 3.3, 1.7, 0.5], [4.8, 3.4, 1.9, 0.2], [5. , 3. , 1.6, 0.2], [5. , 3.4, 1.6, 0.4], [5.2, 3.5, 1.5, 0.2], [5.2, 3.4, 1.4, 0.2], [4.7, 3.2, 1.6, 0.2], [4.8, 3.1, 1.6, 0.2], [5.4, 3.4, 1.5, 0.4], [5.2, 4.1, 1.5, 0.1], [5.5, 4.2, 1.4, 0.2], [4.9, 3.1, 1.5, 0.1], [5. , 3.2, 1.2, 0.2], [5.5, 3.5, 1.3, 0.2], [4.9, 3.1, 1.5, 0.1], [4.4, 3. , 1.3, 0.2], [5.1, 3.4, 1.5, 0.2], [5. , 3.5, 1.3, 0.3], [4.5, 2.3, 1.3, 0.3], [4.4, 3.2, 1.3, 0.2], [5. , 3.5, 1.6, 0.6], [5.1, 3.8, 1.9, 0.4], [4.8, 3. , 1.4, 0.3], [5.1, 3.8, 1.6, 0.2], [4.6, 3.2, 1.4, 0.2], [5.3, 3.7, 1.5, 0.2], [5. , 3.3, 1.4, 0.2], [7. , 3.2, 4.7, 1.4], [6.4, 3.2, 4.5, 1.5], [6.9, 3.1, 4.9, 1.5], [5.5, 2.3, 4. , 1.3], [6.5, 2.8, 4.6, 1.5], [5.7, 2.8, 4.5, 1.3], [6.3, 3.3, 4.7, 1.6], [4.9, 2.4, 3.3, 1. ], [6.6, 2.9, 4.6, 1.3], [5.2, 2.7, 3.9, 1.4], [5. , 2. , 3.5, 1. ], [5.9, 3. , 4.2, 1.5], [6. , 2.2, 4. , 1. ], [6.1, 2.9, 4.7, 1.4], [5.6, 2.9, 3.6, 1.3], [6.7, 3.1, 4.4, 1.4], [5.6, 3. , 4.5, 1.5], [5.8, 2.7, 4.1, 1. ], [6.2, 2.2, 4.5, 1.5], [5.6, 2.5, 3.9, 1.1], [5.9, 3.2, 4.8, 1.8], [6.1, 2.8, 4. , 1.3], [6.3, 2.5, 4.9, 1.5], [6.1, 2.8, 4.7, 1.2], [6.4, 2.9, 4.3, 1.3], [6.6, 3. , 4.4, 1.4], [6.8, 2.8, 4.8, 1.4], [6.7, 3. , 5. , 1.7], [6. , 2.9, 4.5, 1.5], [5.7, 2.6, 3.5, 1. ], [5.5, 2.4, 3.8, 1.1], [5.5, 2.4, 3.7, 1. ], [5.8, 2.7, 3.9, 1.2], [6. , 2.7, 5.1, 1.6], [5.4, 3. , 4.5, 1.5], [6. , 3.4, 4.5, 1.6], [6.7, 3.1, 4.7, 1.5], [6.3, 2.3, 4.4, 1.3], [5.6, 3. , 4.1, 1.3], [5.5, 2.5, 4. , 1.3], [5.5, 2.6, 4.4, 1.2], [6.1, 3. , 4.6, 1.4], [5.8, 2.6, 4. , 1.2], [5. , 2.3, 3.3, 1. ], [5.6, 2.7, 4.2, 1.3], [5.7, 3. , 4.2, 1.2], [5.7, 2.9, 4.2, 1.3], [6.2, 2.9, 4.3, 1.3], [5.1, 2.5, 3. , 1.1], [5.7, 2.8, 4.1, 1.3], [6.3, 3.3, 6. , 2.5], [5.8, 2.7, 5.1, 1.9], [7.1, 3. , 5.9, 2.1], [6.3, 2.9, 5.6, 1.8], [6.5, 3. , 5.8, 2.2], [7.6, 3. , 6.6, 2.1], [4.9, 2.5, 4.5, 1.7], [7.3, 2.9, 6.3, 1.8], [6.7, 2.5, 5.8, 1.8], [7.2, 3.6, 6.1, 2.5], [6.5, 3.2, 5.1, 2. ], [6.4, 2.7, 5.3, 1.9], [6.8, 3. , 5.5, 2.1], [5.7, 2.5, 5. , 2. ], [5.8, 2.8, 5.1, 2.4], [6.4, 3.2, 5.3, 2.3], [6.5, 3. , 5.5, 1.8], [7.7, 3.8, 6.7, 2.2], [7.7, 2.6, 6.9, 2.3], [6. , 2.2, 5. , 1.5], [6.9, 3.2, 5.7, 2.3], [5.6, 2.8, 4.9, 2. ], [7.7, 2.8, 6.7, 2. ], [6.3, 2.7, 4.9, 1.8], [6.7, 3.3, 5.7, 2.1], [7.2, 3.2, 6. , 1.8], [6.2, 2.8, 4.8, 1.8], [6.1, 3. , 4.9, 1.8], [6.4, 2.8, 5.6, 2.1], [7.2, 3. , 5.8, 1.6], [7.4, 2.8, 6.1, 1.9], [7.9, 3.8, 6.4, 2. ], [6.4, 2.8, 5.6, 2.2], [6.3, 2.8, 5.1, 1.5], [6.1, 2.6, 5.6, 1.4], [7.7, 3. , 6.1, 2.3], [6.3, 3.4, 5.6, 2.4], [6.4, 3.1, 5.5, 1.8], [6. , 3. , 4.8, 1.8], [6.9, 3.1, 5.4, 2.1], [6.7, 3.1, 5.6, 2.4], [6.9, 3.1, 5.1, 2.3], [5.8, 2.7, 5.1, 1.9], [6.8, 3.2, 5.9, 2.3], [6.7, 3.3, 5.7, 2.5], [6.7, 3. , 5.2, 2.3], [6.3, 2.5, 5. , 1.9], [6.5, 3. , 5.2, 2. ], [6.2, 3.4, 5.4, 2.3], [5.9, 3. , 5.1, 1.8]])
kwiatki.mean(axis=0)
array([5.84333333, 3.054 , 3.75866667, 1.19866667])
kwiatki.std(axis=0)
array([0.82530129, 0.43214658, 1.75852918, 0.76061262])
np.median(kwiatki, axis=0)
array([5.8 , 3. , 4.35, 1.3 ])
Czytanie z URL-a¶
Funkcja genfromtxt
potrafi czytać dane nie tylko z pliku lokalnego na dysku, ale także bezpośrednio z adresu URL, o ile zasób jest publicznie dostępny bez potrzeby logowania się itp.
adres = "http://students.alx.pl/~pczarnik/dane/iris.data"
kwiatki2 = np.genfromtxt(adres, delimiter=',', usecols=[0,1,2,3])
kwiatki2
array([[5.1, 3.5, 1.4, 0.2], [4.9, 3. , 1.4, 0.2], [4.7, 3.2, 1.3, 0.2], [4.6, 3.1, 1.5, 0.2], [5. , 3.6, 1.4, 0.2], [5.4, 3.9, 1.7, 0.4], [4.6, 3.4, 1.4, 0.3], [5. , 3.4, 1.5, 0.2], [4.4, 2.9, 1.4, 0.2], [4.9, 3.1, 1.5, 0.1], [5.4, 3.7, 1.5, 0.2], [4.8, 3.4, 1.6, 0.2], [4.8, 3. , 1.4, 0.1], [4.3, 3. , 1.1, 0.1], [5.8, 4. , 1.2, 0.2], [5.7, 4.4, 1.5, 0.4], [5.4, 3.9, 1.3, 0.4], [5.1, 3.5, 1.4, 0.3], [5.7, 3.8, 1.7, 0.3], [5.1, 3.8, 1.5, 0.3], [5.4, 3.4, 1.7, 0.2], [5.1, 3.7, 1.5, 0.4], [4.6, 3.6, 1. , 0.2], [5.1, 3.3, 1.7, 0.5], [4.8, 3.4, 1.9, 0.2], [5. , 3. , 1.6, 0.2], [5. , 3.4, 1.6, 0.4], [5.2, 3.5, 1.5, 0.2], [5.2, 3.4, 1.4, 0.2], [4.7, 3.2, 1.6, 0.2], [4.8, 3.1, 1.6, 0.2], [5.4, 3.4, 1.5, 0.4], [5.2, 4.1, 1.5, 0.1], [5.5, 4.2, 1.4, 0.2], [4.9, 3.1, 1.5, 0.1], [5. , 3.2, 1.2, 0.2], [5.5, 3.5, 1.3, 0.2], [4.9, 3.1, 1.5, 0.1], [4.4, 3. , 1.3, 0.2], [5.1, 3.4, 1.5, 0.2], [5. , 3.5, 1.3, 0.3], [4.5, 2.3, 1.3, 0.3], [4.4, 3.2, 1.3, 0.2], [5. , 3.5, 1.6, 0.6], [5.1, 3.8, 1.9, 0.4], [4.8, 3. , 1.4, 0.3], [5.1, 3.8, 1.6, 0.2], [4.6, 3.2, 1.4, 0.2], [5.3, 3.7, 1.5, 0.2], [5. , 3.3, 1.4, 0.2], [7. , 3.2, 4.7, 1.4], [6.4, 3.2, 4.5, 1.5], [6.9, 3.1, 4.9, 1.5], [5.5, 2.3, 4. , 1.3], [6.5, 2.8, 4.6, 1.5], [5.7, 2.8, 4.5, 1.3], [6.3, 3.3, 4.7, 1.6], [4.9, 2.4, 3.3, 1. ], [6.6, 2.9, 4.6, 1.3], [5.2, 2.7, 3.9, 1.4], [5. , 2. , 3.5, 1. ], [5.9, 3. , 4.2, 1.5], [6. , 2.2, 4. , 1. ], [6.1, 2.9, 4.7, 1.4], [5.6, 2.9, 3.6, 1.3], [6.7, 3.1, 4.4, 1.4], [5.6, 3. , 4.5, 1.5], [5.8, 2.7, 4.1, 1. ], [6.2, 2.2, 4.5, 1.5], [5.6, 2.5, 3.9, 1.1], [5.9, 3.2, 4.8, 1.8], [6.1, 2.8, 4. , 1.3], [6.3, 2.5, 4.9, 1.5], [6.1, 2.8, 4.7, 1.2], [6.4, 2.9, 4.3, 1.3], [6.6, 3. , 4.4, 1.4], [6.8, 2.8, 4.8, 1.4], [6.7, 3. , 5. , 1.7], [6. , 2.9, 4.5, 1.5], [5.7, 2.6, 3.5, 1. ], [5.5, 2.4, 3.8, 1.1], [5.5, 2.4, 3.7, 1. ], [5.8, 2.7, 3.9, 1.2], [6. , 2.7, 5.1, 1.6], [5.4, 3. , 4.5, 1.5], [6. , 3.4, 4.5, 1.6], [6.7, 3.1, 4.7, 1.5], [6.3, 2.3, 4.4, 1.3], [5.6, 3. , 4.1, 1.3], [5.5, 2.5, 4. , 1.3], [5.5, 2.6, 4.4, 1.2], [6.1, 3. , 4.6, 1.4], [5.8, 2.6, 4. , 1.2], [5. , 2.3, 3.3, 1. ], [5.6, 2.7, 4.2, 1.3], [5.7, 3. , 4.2, 1.2], [5.7, 2.9, 4.2, 1.3], [6.2, 2.9, 4.3, 1.3], [5.1, 2.5, 3. , 1.1], [5.7, 2.8, 4.1, 1.3], [6.3, 3.3, 6. , 2.5], [5.8, 2.7, 5.1, 1.9], [7.1, 3. , 5.9, 2.1], [6.3, 2.9, 5.6, 1.8], [6.5, 3. , 5.8, 2.2], [7.6, 3. , 6.6, 2.1], [4.9, 2.5, 4.5, 1.7], [7.3, 2.9, 6.3, 1.8], [6.7, 2.5, 5.8, 1.8], [7.2, 3.6, 6.1, 2.5], [6.5, 3.2, 5.1, 2. ], [6.4, 2.7, 5.3, 1.9], [6.8, 3. , 5.5, 2.1], [5.7, 2.5, 5. , 2. ], [5.8, 2.8, 5.1, 2.4], [6.4, 3.2, 5.3, 2.3], [6.5, 3. , 5.5, 1.8], [7.7, 3.8, 6.7, 2.2], [7.7, 2.6, 6.9, 2.3], [6. , 2.2, 5. , 1.5], [6.9, 3.2, 5.7, 2.3], [5.6, 2.8, 4.9, 2. ], [7.7, 2.8, 6.7, 2. ], [6.3, 2.7, 4.9, 1.8], [6.7, 3.3, 5.7, 2.1], [7.2, 3.2, 6. , 1.8], [6.2, 2.8, 4.8, 1.8], [6.1, 3. , 4.9, 1.8], [6.4, 2.8, 5.6, 2.1], [7.2, 3. , 5.8, 1.6], [7.4, 2.8, 6.1, 1.9], [7.9, 3.8, 6.4, 2. ], [6.4, 2.8, 5.6, 2.2], [6.3, 2.8, 5.1, 1.5], [6.1, 2.6, 5.6, 1.4], [7.7, 3. , 6.1, 2.3], [6.3, 3.4, 5.6, 2.4], [6.4, 3.1, 5.5, 1.8], [6. , 3. , 4.8, 1.8], [6.9, 3.1, 5.4, 2.1], [6.7, 3.1, 5.6, 2.4], [6.9, 3.1, 5.1, 2.3], [5.8, 2.7, 5.1, 1.9], [6.8, 3.2, 5.9, 2.3], [6.7, 3.3, 5.7, 2.5], [6.7, 3. , 5.2, 2.3], [6.3, 2.5, 5. , 1.9], [6.5, 3. , 5.2, 2. ], [6.2, 3.4, 5.4, 2.3], [5.9, 3. , 5.1, 1.8]])