NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - NumPy - Tvorba polí

V předchozí lekci, NumPy - Datové typy, jsme se podívali na základní datové typy knihovny NumPy.

V dnešním tutoriálu knihovny NumPy v Pythonu se podíváme na pole v knihovně NumPy a naučíme se je vytvářet. Vysvětlíme si, jak je důležité udržovat pole homogenní.

Úvod do polí ndarrayv NumPy

Pole, která poskytuje knihovna NumPy, se do značné míry chovají podobně jako běžné seznamy v Pythonu. Lze do nich ukládat nejrůznější typy proměnných - čísla, řetězce i obecné objekty a poté k prvkům přistupovat, případně je měnit. Oproti běžným seznamům v Pythonu ale není možné do nich prvky přidávat a odebírat. Pole v NumPy mají pevně daný počet prvků, podobně jako to mají pole v jazycích C či Java.

Rozdíl mezi polem a seznamem

Ještě jednou si zopakujme velmi důležitý poznatek, který jsme zmínili v lekci NumPy - Představení knihovny:

  • Seznamy v Pythonu jsou dynamické. Odpovídají tomu, co v jiných jazycích označujeme jako list - seznam.
  • Oproti seznamům se v NumPy jedná o skutečná pole - array, jako je známe z jazyků C či Java. V NumPy je označujeme také jejich technickým názvem jako ndarray.

Nativní seznamy Pythonu a pole NumPy budeme v tutoriálu striktně odlišovat.

Ukažme si ještě pro jistotu kód seznamu a pole:

seznam = [1, 2, 3]    # seznam
print(type(seznam))

pole = np.array([1, 2, 3])    # ndarray
print(type(pole))

Ve výstupu konzole dostaneme:

Rozdíl mezi seznamem a polem:
class 'list'
class 'numpy.ndarray'

Kdy použít pole, kdy seznam?

Proč bychom měli používat NumPy ndarray, když nám oproti Pythonovskému seznamu neumožňuje přidávat a odebírat prvky? Odpovědi jsou dvě: čas a prostor v paměti. S polem se počítači zachází jednodušeji. Jakmile se jednou pole vytvoří v paměti, jeho délka zůstává až do smazání Garbage Collectorem konstantní. Samozřejmě se občas nějaká hodnota v něm změní, ale to je vše.

Proto pokud pracujeme s velkým množstvím hodnot nebo operací, je obecně rychlejší i úspornější použít ndarray. Jinak samozřejmě můžeme použít i základní Python seznam.

Tvorba ndarray polí v NumPy

Existuje více způsobů, jak ndarray vytvořit. Nejčastěji použijeme "přeměnu" seznamu pomocí metody np.array(). NumPy nicméně obsahuje mnoho dalších zajímavých funkcí a metod, které poskytují na výstupu ndarray. Podívejme se na některé z nich.

Vytvoření NumPy pole z Python seznamu

Nejprve si ukážeme již zmíněnou metodu np.array():

prirozena_cisla_pole = np.array([1, 2, 3])
zvirata_pole = np.array(['pes', 'kočka', 'pterodaktyl'])
datum_pole = np.array([np.datetime64('2023-07-20T17:23:10.42'), np.datetime64('2023-07-20'), np.datetime64('2023-07')])

Obecně je nevhodné míchat různé typy v jednom poli. Datový typ NumPy pole, při jeho vytvoření, buď explicitně specifikujeme, nebo je automaticky určen na základě hodnot, které do pole vložíme. Pokud vložíme do jednoho pole různé typy dat, NumPy je všechny převede na jednotný typ. Vybere přitom takový, který dokáže reprezentovat všechny vložené hodnoty.

Uveďme si příklad. Pokud vytvoříme pole s celými čísly a jedno z nich bude desetinné, všechna čísla budou převedena na desetinná. Podobně, pokud přidáme řetězec do pole s celými čísly, všechna čísla budou převedena na řetězce. Je zřejmé, jak nepěkně toto dokáže ovlivnit výsledky matematických operací.

Přetypování v poli je nákladné z hlediska výkonu a jde o velmi snadný způsob, jak si přidělat opravdu nepříjemné problémy s neočekávaným chováním programu. Proto se snažíme pole udržovat homogenní.

Pokud budeme opravdu kreativní a do jednoho pole namixujeme tolik typů, že NumPy nedokáže najít jeden, kterým by je zastřešil, vznikne nám pole prvků object:

mix_pole = np.array([1, 'pes', np.datetime64('2023-07-20T17:23:10.42')])
print(mix_pole.dtype)

Ve výstupu uvidíme:

Typ prvků pole:
object

Tvorba vícerozměrných polí

Pojďme si ukázat, jak s pomocí metody np.array() vytvoříme vícerozměrná pole:

pole_2D = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
pole_3D = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
Přístup k prvkům v 3D poli

Naše pole_3D má formát 2 x (2 x 3). Představme si ho jako kinosál. Formát 2 x (2 x 3) nám říká, že máme přízemí a patro a v každém z nich dvě řady po třech sedadlech. Rozložme si zápis pole tak, aby byl intuitivnější:

pole_3D = np.array([
[[1, 2, 3],    # přízemí, první řada
[4, 5, 6]],    # přízemí, druhá řada
[[7, 8, 9],    # patro, první řada
[10, 11, 12]]  # patro, druhá řada
])

# Přístup k sedadlu číslo 12 v patře:
sedadlo = pole_3D[1, 1, 2]  # v proměnné sedadlo bude číslo 12

Zajímavostí je, že můžeme vytvořit i pole s "dimenzí 0":

pole_0D = np.array(10)

V podstatě tím do pole uložíme jen jednu hodnotu. Pokud vytiskneme obsah proměnné pole_0D, dostaneme hodnotu 10. Pokud však zjistíme typ proměnné, dostaneme ndarray, nikoli integer:

print(pole_0D)
print(type(pole_0D))

V konzoli uvidíme:

Pole s dimenzí 0:
10
<class 'numpy.ndarray'>

Náhodné celé číslo np.random.randint()

Metoda randint() v modulu random knihovny NumPy je základní funkce pro generování náhodných čísel typu integer. Jak pro vygenerování jedné náhodné hodnoty, tak i celého (i vícerozměrného) pole náhodných hodnot.

Funkce a metody v modulu random máme k dispozici buď přímo z knihovny np.random, nebo si modul přidáme přímo jako proměnnou. To je způsob, jaký budeme používat v tutoriálu kvůli zjednodušení kódu:

import numpy.random as random

Nyní už můžeme proměnnou random používat přímo.

Metodu randint() již známe z kurzu Základní konstrukce jazyka Python. Nechme si tedy vygenerovat náhodné číslo od nuly do devatenácti:

nahodne_cislo = random.randint(20)

Je potřeba si uvědomit, že jako mnoho dalších knihoven a funkcí v Pythonu, i NumPy používá spodní definovanou hranici intervalu "včetně" (inkluzivní) a horní hranici "bez" (exkluzivní). V našem případě kód random.randint(20) znamená v řeči matematiky interval <0; 20).

Pole náhod :-)

Pokud chceme vytvořit pole náhodných hodnot, vyplníme metodě argument požadované délky pole size:

pole_nahodnych_cisel = random.randint(3, 20, size=(5)) # znamená naplň pole o délce 5 čísel čísly od 3 do 19
print(pole_nahodnych_cisel)
print()
pole_2D_nahodnych_cisel = random.randint(3, 20, size=(5, 4)) # naplň pole o pěti řádcích a čtyřech sloupcích čísly od 3 do 19
print(pole_2D_nahodnych_cisel)

Výstup v konzoli:

Konzolová aplikace
[ 8  7  7  5 17]

[[19  8 14  8]
 [14  5  5  3]
 [ 4  6 17 10]
 [16 14  5  6]
 [19 18  8  9]]

Náhodný double - np.random.rand()

Metoda rand() má trochu odlišnou syntaxi. Tato metoda generuje náhodné číslo mezi 0 a 1. Opět v half-open intervalu, ovšem tentokrát <0; 1). Pokud chceme získat desetinné číslo v jiném intervalu, musíme funkci rand() přenásobit a posunout. Řekněme, že chceme náhodné číslo v intervalu <10, 30):

nahodne_desetinne_cislo = random.rand() * 20 + 10

Více si o náhodných číslech řekneme v dalších lekcích. Teď se přesuneme k vytváření polí. NumPy ndarray pomocí metody rand() vytvoříme tak, že do argumentu dáme číslo označující rozměr pole, které chceme:

# Pole náhodných čísel délky 3
nahodne_1D_pole = random.rand(3)

Získali jsme pole tří čísel z intervalu <0,1). Podobně vytvoříme i vícerozměrná pole - prostě jen přidáme číslo označující další rozměr:

# Matice náhodných čísel o rozměrech 3×4
nahodne_2D_pole = random.rand(3, 4)

Pro čísla v jiném intervalu než <0,1) opět použijeme posunutí násobením a přičtením čísla.

To je pro tuto lekci vše.

V následující lekci, NumPy - Základní operace s poli, si vysvětlíme základní operace s NumPy poli. Konkrétně si ukážeme indexaci a procházení polí.


 

Předchozí článek
NumPy - Datové typy
Všechny články v sekci
NumPy - Matematika v Pythonu
Přeskočit článek
(nedoporučujeme)
NumPy - Základní operace s poli
Článek pro vás napsal Miloš Halda
Avatar
Uživatelské hodnocení:
21 hlasů
Autor se věnuje především bioinformatice a s ní souvisejícím tématům. Nevyhýbá se OOP jazykům, statistice a nástrojům pro analýzu dat.
Aktivity