In [ ]:
# Instalace
Nejdříve si nainstaluj tyhle knihovny:
* Numpy
* Pillow
* Matplotlib
* IPython Notebook
* Pandas
* Pygments
Tenhle typ knihoven je nechvalně známý tím, že je docela složité je nainstalovat. I proto, že jsou zčásti napsané v jiných jazycích než je Python. V poslední době se ale jejich instalace zjednodušuje, tak to snad zvládneš i ty!
## Windows
Numpy jde nainstalovat z; www.lfd.uci.edu/~gohlke/pythonlibs/#numpy (stáhnout a soubor nainstalovat `pip install soubor.whl`); ostatní by snad měly jít pomocí `python -m pip install jméno-knihovny`, tedy:
> python -m pip install pillow matplotlib ipython[notebook] pandas pygments
## Linux
Nejdřív je potřeba nainstalovat závislosti. Pro Fedoru:
$ sudo yum install python3-devel zlib-devel Cython atlas-devel lapack-devel gcc gcc-gfortran zlib-devel tk-devel libpng-devel freetype-devel libjpeg-turbo-devel
A pak, ve virtuálním prostředí:
$ python -m pip install numpy pillow matplotlib ipython[notebook] pandas pygments
IPython je nástroj, který zjednodušuje interaktivní práci v Pythonu, zvlášť výpočty a experimenty. Dá se spustit z příkazové řádky jako ipython
– pak se chová podobně jako python
, jen s barvičkama a různýma vychytávkama navíc.
My si ale vyzkoušíme IPython Notebook, který běží v prohlížeči, a umožní nám se vracet k předchozím příkazům, zobrazovat obrázky, nebo třeba prokládat kód hezky formátovanými poznámkami (jako je ta, kterou právě čteš).
Zadej:
$ ipython notebook
IPython Notebook se ovládá docela intuitivně: do políčka napíšeš kód, zmáčkneš Shift+Enter. Kód se provede, zobrazí se výsledek, a objeví se políčko pro další kousek kódu. Když je kód špatně, dá se opravit a pomocí Shift+Enter spustit znovu.
In [4]:
import numpy
pole = numpy.array([0, 1, 2, 3, 4, 5, 6])
pole
Out[4]:
In [5]:
pole[0]
Out[5]:
In [6]:
pole[1:-2]
Out[6]:
In [7]:
pole[0] = 9
pole
Out[7]:
V jiných ohledech se ale chová jinak. Například takovému poli nejde měnit velikost – nemá metody jako append
:
In [8]:
pole.append(1)
Další zajímavost je, že pole má daný typ prvků. Když uděláme pole celých čísel, nejdou do něj pak vkládat třeba řetězce:
In [9]:
pole[0] = 'ahoj'
... a pokud do takového pole přiřadíme desetinné číslo, zaokrouhlí se dolů (pomocí funkce int
):
In [10]:
pole[0] = 3.9
pole
Out[10]:
Typ pole se dá zadat při jeho vytváření, pomocí argumentu dtype
.
In [11]:
pole_float = numpy.array([0, 1, 2, 3, 4, 5, 6], dtype=float)
pole_float
Out[11]:
In [12]:
pole_str = numpy.array([0, 1, 2, 3, 4, 5, 6], dtype=str)
pole_str
Out[12]:
In [13]:
pole1 = numpy.array(range(10))
pole1
Out[13]:
In [14]:
pole1 + 5
Out[14]:
In [15]:
pole1 / 4
Out[15]:
In [16]:
pole2 = numpy.array(range(-10, 20, 3))
pole2
Out[16]:
In [17]:
pole1 + pole2
Out[17]:
In [18]:
pole1 * pole2
Out[18]:
A jak spojit dvě pole dohromady, tak jak to dělá +
u seznamů? Na to má Numpy speciální funkci hstack
.
In [19]:
numpy.hstack([pole1, pole2])
Out[19]:
Všechny funkce Numpy se dají najít v domkumentaci, i když nezasvěcení v ní můžou ze začátku docela tápat. Základní matematické funkce jso popsány pod "Available ufuncs".
In [20]:
numpy.sin(pole)
Out[20]:
Ještě pozor na to, že i porovnávací operátory pracují na jednotlivých prvcích. Vznikle pole bool
ů.
In [21]:
pole1 < pole2
Out[21]:
Pokud budeš chtít takové pole použít v if
u, použij funkci any
(vrací True
pokud jsou některé z prvků true) nebo all
(vrací True
pokud jsou všechny prvky true)
In [22]:
if any(pole1 < pole2):
print('Některé prvky pole1 jsou menší než odpovídající prvky pole2')
if all(pole1 < pole2):
print('Všechny prvky pole1 jsou menší než odpovídající prvky pole2')
V praxi jsou pole, se kterými se dělá nějaké to zpracovávání dat, obrovská.
Udělej si pole s milionem prvků, pomocí funkce linspace
která bere minimální a maximální hodnotu, a délku pole. (Zabere to několik MB paměti; pokud máš menší počítač, zkus třeba jen 10 tisíc.)
In [23]:
x = numpy.linspace(-10, 10, 1000000)
x
Out[23]:
Pak na všechna tahle čísla zároveň zavolej funkci sin
.
Všimni si jak je to rychlé – kdybys na to použila pythoní cyklus for
, trvalo by to mnohem déle. Obecně je dobré, když děláš výpočty pomocí Numpy, používat pole a vestavěné funkce místo Pythoních cyklů.
In [24]:
sin_x = numpy.sin(x)
sin_x
Out[24]:
A teď si ten sinus výstup nakresli pomocí knihovny matplotlib
. Nejdřív nějaké ty importy a nastavení: řádek začínající %
je IPythonová vychytávka, která způsobí že se grafy vykreslí pr'imo v prohlížeči.
In [45]:
from matplotlib import pyplot
%matplotlib inline
Teď stačí použít funkci matplotlib.pyplot.plot
, která bere (v základu) dva argumenty – pole hodnot pro x
-ovou osu, a pole hodnot pro osu y
-ovou.
In [26]:
pyplot.plot(x, sin_x)
Out[26]:
Pole z Numpy ale nemusí být jen řady čísel. Můžou to být i tabulky čísel! Dvou- (a více-)rozměrným polím se říká matice, a chovají se trochu jako seznamy seznamů.
In [27]:
matice = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
matice
Out[27]:
In [28]:
matice[0]
Out[28]:
In [29]:
matice[0:-1]
Out[29]:
In [30]:
matice[0][2]
Out[30]:
Na rozdíl od seznamů seznamů se matice dají indexovat dvojicí čísel (nebo složitějších indexů), oddělených čárkou. Dají se tak jednoduše vybírat celé řádky nebo sloupce.
In [31]:
matice[0, 2]
Out[31]:
In [32]:
matice[0, 1:]
Out[32]:
In [33]:
matice[:, :2]
Out[33]:
In [34]:
matice[::2, ::2]
Out[34]:
A do vybraných řádků nebo sloupců se dají i přiřazovat hodnoty.
In [35]:
matice2 = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
matice2
Out[35]:
In [36]:
matice2[1, 1] = 0
matice2
Out[36]:
In [37]:
matice2[::2, ::2] = 0
matice2
Out[37]:
In [38]:
matice2[::2, ::2] = numpy.array([[-1, -3], [-7, -9]])
matice2[1, 1] = -5
matice2
Out[38]:
Pomocí knihovny matplotlib
si můžeme matici "nakreslit" jako orázek.
In [39]:
pyplot.imshow(matice2, interpolation='none', cmap='gray')
# Pojmenované argumenty specifikují jak přesně se graf vykreslí:
# interpolation='none' má smysl pro malé matice, a
# cmap='gray' vykresluje v odstínech šedi:
# černá je nejmenší číslo, bílá největší
Out[39]:
Když každému číslu přiřadit barvu,
In [40]:
obrazek = numpy.zeros([100, 100])
for x in range(-50, 50):
for y in range(-50, 50):
obrazek[x+50, y+50] = x ** 2 + y ** 2
pyplot.imshow(obrazek)
Out[40]:
Jak je napsáno výše, je lepší nepoužívat for
-cykly, protože s velkou spoustou čísel by to bylo pomalé. Numpy má spoustu funkcí, které dokážou cykly nahradit – jen je potřeba je znát, či umět najít v dokumentaci.
In [46]:
n = numpy.linspace(-50, 50, 1000)
x, y = numpy.meshgrid(n, n)
z = x ** 2 + y ** 2
pyplot.imshow(z)
Out[46]:
Pole v Numpy mohou mít i více rozměrů než dva. Trojrozměrná matice je jako seznam seznamů seznamů. Každý pixel v obrázku, který jsme kreslily před chvílí, by sám obsahoval několik hodnot.
Příklad trojrozměrné matice je počítačový obrázek – pro každý pixel se zapisuje intenzita červené, zelené a modré barvy (angl. red, green, blue; RGB) – tedy 3 hodnoty.
In [39]:
from PIL import Image
# Obrázek © Mokele, http://en.wikipedia.org/wiki/User:HCA
# http://commons.wikimedia.org/wiki/File:Ball_python_lucy.JPG
krajta = numpy.array(Image.open('krajta.jpg'))
krajta
Out[39]:
Funkce imshow
si s takovou věcí poradí, a nakreslí obrázek správných barev.
(Jen si pořád myslí že to je graf, tak automaticky doplní osy.)
In [40]:
pyplot.imshow(krajta)
Out[40]:
Indexování funguje stejně jako u dvourozměrných polí. V případě obrázků představuje první číslo řádek, druhé sloupec, ...
In [41]:
pyplot.imshow(krajta[400:-200, 0:300])
Out[41]:
... a třetí index je barva. Můžeš třeba snížit intenzitu modré, aby obrázek zežloutl:
In [42]:
krajta[:, :, 2] = krajta[:, :, 2] / 2
pyplot.imshow(krajta)
Out[42]:
(A aby se nemuselo při indexování vícerozměrných polí opakovat :, :, :, :
, dá se to nahradit třemi tečkami:)
In [43]:
krajta[..., 0] = krajta[..., 0] / 2
pyplot.imshow(krajta)
Out[43]:
Tak, teď když něco víš o tom, jak funguje Numpy a jeho pole, můžeš se (s trochou googlení) směle pustit do analýzy obrazů, zvuků, matematických funkcí nebo fyzikálních simulací. Pokud znáš např. Matlab, zkus googlit "Python" + jméno funkce v Matlabu; často zjistíš že Numpy (nebo jiná knihovna, třeba Scipy) podobnou funkci obsahuje taky. A že na její použití nepotřebuješ drahou licenci :)
Většina dat, které se analyzují, nebudou matice jako takové, ale budou to tabulky se sloupečky. My zkusíme zpracovat data ze sčítání lidu, domů a bytů, které zveřejňuje Český statistický úřad. Nejvhodnější formát pro stažení je pro nás je CSV; pro porozumění si stáhni i "Popis dat" v PDF.
Koukni se stažený soubor v textovém editoru, ať vidíš o co jde. Pak ho načti pomocí Pandas:
In [44]:
import pandas
data = pandas.read_csv('SLDB_ZV.CSV', encoding='cp1250')
data.head() # metoda head() nám ukáže jen prvních pár řádků, aby výpis nebyl tak dlouhý.
Out[44]:
Názvy sloupců od ČSÚ nedávají moc smysl, tak si je přejmenuj:
In [45]:
data.columns = ['typ', 'název', 'číslo', 'kód',
'obyvatel', 'muži', 'ženy', 'obyv_0', 'obyv_15', 'obyv_65',
'aktivní', 'zamestnaní', 'domy', 'byty', 'domácnosti']
data.head()
Out[45]:
Data v Pandas tabulce se dají indexovat, ale na rozdíl od matic, indexy vybírají sloupce. Pokud chceš vybrat řádek musíš napsat:
In [46]:
data.loc[10]
Out[46]:
Sloupce se pak indexují jménem (řetězcem), nikoli číslem:
In [47]:
data['obyvatel']
Out[47]:
Možná sis v předchozím výstupu všimla levého sloupce, který obsahuje čísla řádků. Pandas mu říká index. Je to speciální sloupec, který "pojmenovává" celou řádku, a vypisuje se na příhodných místech. Bylo by fajn tam mít místo čísla jméno.
Index se dá se změnit, ale musíš si dávat pozor, aby neobsahoval duplikáty. V ČR je 15 obcí jménem 'Nová Ves'
, takže nemůžeme jednoznačně pojmenovat jenom jménem.
Naštěstí Pandas umí takzvané složené indexy, takže můžeme zkombinovat číslo řádku (kvůli unikátnosti) a jméno (pro přehlednost):
In [48]:
data.set_index([data.index, 'název'], drop=False, inplace=True)
data.head()
Out[48]:
In [49]:
data['obyvatel']
Out[49]:
Při aritmetických operacích se sloupečky chovají podobně jako matice: operace se provede nad odpovídajícími hodnotami. Dá se třeba jednoduše zjistit poměr počtů mužů a žen:
In [50]:
data['ženy'] / data['muži']
Out[50]:
Následující kód přidá vypočítaná data do tabulky jako nový sloupec:
In [51]:
data['poměr'] = data['ženy'] / data['muži']
data.head()
Out[51]:
Podobně jako /
se dá použít i většina ostatních operátorů, třeba ==
:
In [52]:
data['typ'] == 'kraj'
Out[52]:
A speciální vychytávka: sloupcem typu bool
se dá indexovat, a vybrat tak příslušné řádky tabulky.
Takhle se tvoří tabulka, ve které jsou jenom kraje:
In [53]:
kraje = data[data['typ'] == 'kraj']
kraje
Out[53]:
Když budeš chtít vybrat víc sloupců, dá se indexovat i seznamem řetězců:
In [54]:
kraje[['název', 'číslo']]
Out[54]:
No a nakonec si ukážeme nějaké ty grafy a obrázky.
In [55]:
kraje[['muži', 'ženy']].plot(kind='bar')
Out[55]:
In [56]:
kraje.plot(kind='scatter', x='domy', y='byty', s=kraje['domácnosti']/1000)
Out[56]:
a další viz dokumentace k funkci plot()