--- title: "Proměnné" author: "Michal Kvasnička" documentclass: article output: html_document: theme: cerulean toc: yes toc_float: yes pdf_document: default fontsize: 10pt classoption: a4paper --- # Proměnné Málo kdy pracujeme s\ daty přímo jako s\ čísly. V\ případě velkých dat by to ani nebylo možné. Místo toho svá data uložíme do proměnných a dále pracujeme s\ těmito proměnnými. Kromě usnadnění práce to má ještě jednu výhodu: naše skripty jsou tak obecnější. Můžeme např.\ napsat analytický kód s\ pomocí dat z\ pilotního průzkumu, a\ pak jej spustit znovu ve chvíli, kdy doběhl celý sběr dat, s\ novými daty. Vyměníme jen datový soubor a jinak nemusíme svůj kód vůbec měnit. V\ této kapitole se naučíte - co jsou proměnné a k\ čemu slouží - jaká jména proměnných jsou povolená (a\ jak tuto restrikci obejít) - jak přiřadit do proměnné hodnotu - jak vypsat obsah proměnné - jak proměnnou smazat - jak zjistit, jaká metadata proměnná obsahuje, a\ jak je změnit ## K čemu slouží proměnné Koncept proměnné znáte z\ matematiky. Tam je proměnná "krycí název" pro nějakou hodnotu, např.\ pro číslo\ 5. Krása proměnných spočívá v\ tom, že umožňují počítat zcela obecně. Pokud např.\ označíme délku trasy v\ kilometrech písmenem\ $s$ a rychlost jízdy v\ kilometrech za hodinu písmenem\ $v$, pak víme, že vzdálenost\ $s$ ujedeme za $s/v$ hodin. Tento výsledek platí bez ohledu na to, jak daleko a jak rychle jedeme. Jak už naznačuje název proměnná, můžeme hodnotu proměnné měnit, a\ výraz $s/v$ vyhodnotit pokaždé znovu. Pro jednoduchý výpočet, který jsme právě uvažovali, nemusí být takové zobecnění příliš užitečné, ale při složitých výpočtech nad velkými daty je zavedení proměnných velká pomoc. V\ počítači plní proměnné stejnou úlohu jako v\ matematice: uchovávají nějakou hodnotu. Můžeme počítači říct, co má s\ touto hodnotou dělat, bez toho, abychom přesně věděli, jaká tato hodnota je. I\ když to technicky není přesné, můžeme si proměnnou představit jako krabičku, do které se vloží nějaká hodnota. Každá proměnná může v\ jednom okamžiku obsahovat vždy jen jednu hodnotu. Pokud do proměnné uložíme novou hodnotu, stará hodnota se ztratí. Slovo "hodnota" je však třeba brát volně: "hodnota" může být stejně dobře jedno číslo jako složitá struktura složená z\ čísel, textů a jiných objektů. (Technicky přesnější je říct, že proměnná jméno, které se odkazuje na nějakou oblast v\ paměti počítače, kde jsou uložena naše data. Aby počítač věděl, jak s\ daným kusem paměti zacházet, musí vědět, jakého typu jsou uložená data, např.\ zda se jedná o\ celá čísla nebo o\ text, a\ v\ jaké datové struktuře jsou data uložena, např.\ ve vektoru.) R\ je volně typovaný jazyk. To znamená, že typ proměnné nemusíte nijak deklarovat a R\ jej samo odhadne podle vložené hodnoty. Do proměnné můžete v\ jedné chvíli uložit číslo a později toto číslo nahradit třeba kusem textu. R\ si s\ tím poradí. (Proměnná bude prostě nejdříve odkazovat na jedno místo v\ paměti, a\ pak na jiné. Nepoužívanou oblast paměti R samo uvolní.) ## Jména proměnných {#sec:variables-names} Jména proměnných musí splňovat určité vlastnosti. Jméno proměnné se může skládat jen z\ písmen, číslic, teček a podtržítek a musí začínat písmenem nebo tečkou, za kterou nenásleduje číslice. Jména `a`, `a2`, `myNumber`, `my_number`, nebo `.my.way` jsou přípustná; jména jako `2way`, `.2way` nebo `my-number` nejsou povolená. Stejně tak nejsou povolená rezervovaná slova: `if`, `else`, `repeat`, `while`, `function`, `for`, `in`, `next`, `break`, `TRUE`, `FALSE`, `NULL`, `Inf`, `NaN`, `NA`, `NA_integer_`, `NA_real_`, `NA_complex_` a `NA_character_`. Ve jménech proměnných záleží na velikosti písmenem, takže `x` a `X` jsou dvě různé proměnné. Jméno proměnné by ideálně mělo být stručné a mělo by výstižně popisovat, jakou hodnotu proměnná obsahuje. Pokud se jméno skládá z\ více slov, slova se historicky oddělovala tečkami (např.\ `pv.of.bond`). V\ současné době se to nedoporučuje, protože tečky se používají i\ k\ oddělení generické a specifické části jmen objektových metod, viz kapitola\ \@ref(kap:objekty). Místo toho se doporučuje používat podtržítka (`pv_of_bond`) nebo případně tzv.\ "Camel Case" standard (`pvOfBond`), který však v\ R\ není příliš obvyklý. Pokud si nejste jistí, jak jméno proměnné sestavit, může vám pomoci funkce `make.names()`, která převede zadaný řetězec na syntakticky platné jméno proměnné, ovšem bohužel s\ tečkami: ```r make.names("pv of bond") ``` ``` ## [1] "pv.of.bond" ``` Někdy je potřeba pracovat s\ proměnnou, jejíž jméno není v\ R povoleno. (Taková situace nejčastěji vznikne při importu dat z\ jiného softwaru.) Proměnnou s\ nelegálním jménem můžete použít, pokud její jméno uzavřete mezi dva zpětné apostrofy ("backticks"). Jméno proměnné nemůže obsahovat (mimo jiné) mezeru. Pomocí zpětných apostrofů však můžete pracovat i\ s\ proměnnou, jejíž jméno mezeru obsahuje: ```r `ahoj lidičky!` <- 5 2 * `ahoj lidičky!` ``` ``` ## [1] 10 ``` I\ když je možné používat i\ "nedovolená" jména proměnných, výrazně to nedoporučujeme. ## Přiřazení hodnoty do proměnné Hodnoty se do proměnných přiřazují pomocí "šipky" `<-`, kde šipka vždy ukazuje ke jménu proměnné, zatímco na druhé straně je výraz, který má R vyhodnotit. V\ RStudiu lze šipku vložit pomocí klávesové zkratky `Alt-`. (Funguje i\ šipka\ `->` otočená opačným směrem. Tuto kuriozitu však používá jen p.\ Mikula a výrazně vám nedoporučuji ji používat, protože při čtení kódu zjistíte, co se s\ daným výrazem stane, až na konci možná velmi dlouhé konstrukce.) Někteří lidé používají k\ přiřazení do proměnné i\ symbol rovnítka (`=`). To nedoporučuji. Rovnítko v\ některých kontextech funguje jako synonymum šipky, zatímco v\ jiných ne (tam rovnítko znamená něco jiného). Použití rovnítka k\ přiřazení je tak matoucí. Detaily najdete na https://goo.gl/Tnu8Q5. Příklad: ```r x <- (2 + 3) * 4 # x má nyní hodnotu 20 x # jak se vzápětí přesvědčíme ``` ``` ## [1] 20 ``` ## Vypsání hodnoty proměnné do konzoly Při přiřazení hodnoty do proměnné se výsledek nevypíše. Pokud jej chcete vypsat, musíte o\ to R požádat. To můžete udělat třemi způsoby: 1)\ explicitně vypsat obsah proměnné pomocí funkce `print()`, 2)\ implicitně vypsat obsah proměnné tak, že napíšete její jméno do konzoly (R\ volá implicitně funkci `print()` za vás) nebo 3)\ tak, že celý výraz přiřazení zabalíte do závorek. ```r x <- "This is some text." # hodnota se přiřadí, nic se nevypíše x # implicitní vypsání hodnoty proměnné x ``` ``` ## [1] "This is some text." ``` ```r print(x) # explicitní vypsání hodnoty proměnné x ``` ``` ## [1] "This is some text." ``` ```r (y <- 2) # výraz se vyhodnotí a hodnota implicitně vypíše ``` ``` ## [1] 2 ``` Implicitní forma vypsání obsahu proměnné je vhodná pro interaktivní práci v\ konzoli, nemusí však fungovat uvnitř funkcí a skriptů, protože ve skutečnosti jen žádáte R o\ vrácení hodnoty proměnné. Podle kontextu může být vrácená proměnná využita různě. V\ konzoli se využije tak, že konzola na hodnotu zavolá funkci `print()`. Uvnitř funkce však může být vrácená hodnota použitá funkcí jinak. Uvnitř funkcí a podobných struktur je tedy třeba obsah proměnné vypsat explicitně pomocí funkce `print()`. To, jak R vypíše obsah proměnné, se může lišit od skutečného obsahu dané proměnné. R\ totiž pro různé objekty volá různé varianty funkce `print()` přizpůsobené těmto objektům a může vypsat více nebo méně informací, než je jich v\ dané proměnné obsaženo. To, jak vypisuje data pro základní datové typy a struktury se dozvíte v\ následujících dvou kapitolách. Někdy proměnná obsahuje mnoho hodnot (např.\ dlouhý vektor, tabulku s\ mnoha řádku apod.) a my ji nechceme vypsat celou, nýbrž z\ ní chceme získat jen nějakou ukázku, typicky několik prvních nebo posledních hodnot. Několik prvních hodnot vrací funkce `head()`, posledních hodnot funkce `tail()`. Obě vrací implicitně 6\ hodnot (prvků vektoru, řádků matice apod.); tento počet lze změnit nastavením parametru\ `n`: ```r x <- matrix(1:1200, ncol = 3) # vytvoří matici se 400 řádky head(x) # vypíše 6 prvních řádků matice ``` ``` ## [,1] [,2] [,3] ## [1,] 1 401 801 ## [2,] 2 402 802 ## [3,] 3 403 803 ## [4,] 4 404 804 ## [5,] 5 405 805 ## [6,] 6 406 806 ``` ```r head(x, n = 3) # vypíše 3 první řádky matice ``` ``` ## [,1] [,2] [,3] ## [1,] 1 401 801 ## [2,] 2 402 802 ## [3,] 3 403 803 ``` ```r tail(x) # vypíše 6 posledních řádků matice ``` ``` ## [,1] [,2] [,3] ## [395,] 395 795 1195 ## [396,] 396 796 1196 ## [397,] 397 797 1197 ## [398,] 398 798 1198 ## [399,] 399 799 1199 ## [400,] 400 800 1200 ``` Pokud pracujete v\ RStudiu, můžete použít k\ zobrazení obsahu proměnné i\ funkci `View()`. Tato funkce otevře novou záložku a zobrazí obsah proměnné. Způsob zobrazení závisí na datové struktuře. Atomické vektory, matice a tabulky zobrazí ve formě interaktivní tabulky, která umožňuje hodnoty třídit a filtrovat. Seznamy a objekty postavené nad seznamy se zobrazí podobně, jako je vypisuje funkce `str()`. Funkci `View()` je možné vyvolat i\ pomocí myši tak, že v\ záložce `Environment` kliknete na ikonku tabulky (tabulární pohled) nebo trojúhelníku vedle jména proměnné. Pozor: seznam proměnných musí být v\ režimu "List". ## Atributy (metadata) Proměnné v\ R obsahují kromě vlastních hodnot také metadata (informace o\ datech). V\ R se metadata nazývají atributy. Funkce `attributes()` vypíše seznam všech atributů dané proměnné. ```r x <- c(a = 1, b = 2, c = 3) # vektor s pojmenovanými prvky x ``` ``` ## a b c ## 1 2 3 ``` ```r attributes(x) ``` ``` ## $names ## [1] "a" "b" "c" ``` ```r X <- matrix(1:12, nrow = 3) # matice má počet řádků a sloupců X ``` ``` ## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12 ``` ```r attributes(X) ``` ``` ## $dim ## [1] 3 4 ``` Atributy proměnných mohou zahrnovat třídu objektu, dimenze proměnných (počet řádků, sloupců a případně dalších rozměrů objektu), jména řádků, sloupců, jednotlivých prvků vektorů a případně další informace. Hodnotu jednoho atributu je možné získat funkcí `attr()`; tuto funkci je zároveň možné použít i\ ke změně hodnoty atributu (ve skutečnosti se volá jiná funkce, syntaxe však vypadá stejně): ```r attr(x, "names") ``` ``` ## [1] "a" "b" "c" ``` ```r attr(x, "names") <- c("Ahoj", "Bum", "Cak") attr(x, "names") ``` ``` ## [1] "Ahoj" "Bum" "Cak" ``` ```r x ``` ``` ## Ahoj Bum Cak ## 1 2 3 ``` Pokud se zeptáte na hodnotu atributu, který není v\ proměnné přítomen, funkce `attr()` vrací hodnotu `NULL`: ```r attr(x, "coriandr") ``` ``` ## NULL ``` Atribut zrušíte tak, že do něj přiřadíte hodnotu `NULL`. ```r attr(x, "names") <- NULL x ``` ``` ## [1] 1 2 3 ``` ## Smazání proměnné Ke smazání proměnné z\ aktuálního prostředí slouží funkce `rm()`: ```r rm(x) # smaže proměnnou x rm(x, y, z) # smaže proměnné x, y a z rm(list = ls()) # smaže všechny proměnné z aktuálního prostředí ``` V\ RStudiu můžete proměnné mazat i\ myší. V\ záložce `Environment` k\ tomu slouží ikonka koštěte. Pokud máte proměnné zobrazené v\ režimu `Grid`, můžete vybrat, které proměnné budou smazány. V\ režimu `List` budou smazány všechny proměnné. Někdy je však potřeba vyčistit paměť\ R důkladněji. Smazání všech proměnných totiž stále zanechá v\ R mnoho změn: načtené balíky, změněné cesty apod. Nejdůkladnější vyčištění pracovního prostředí přestavuje restart\ R. V\ RStudiu je to možné udělat v\ menu `Session`$\rightarrow$`Restart R` nebo pomocí klávesové zkratky `Ctrl`-`Shift`-`F10`. Pokud si chcete ověřit, že váš skript běží spolehlivě, vždy byste jej měli vyzkoušet v\ čistém prostředí\ R, tj.\ po jeho restartu. ## Aplikace: výpočet dojezdové vzdálenosti Jako příklad práce s\ proměnnými vytvoříme jednoduchý skript, který spočítá, za jak dlouho dorazíme do cíle. Nejdříve si vyčistíme pracovní prostředí smazáním všech dříve vytvořených proměnných (což je velmi užitečný zvyk). Následně vytvoříme proměnné vzdálenost a rychlost, pak vypočteme dobu jízdy a vypíšeme ji. Náš skript bude tedy vypadat takto: ```r rm(list = ls()) vzdalenost <- 1079 # vzdálenost z Brna do Dubrovniku v km rychlost <- 90 # očekávaná průměrná rychlost v km / h doba_jizdy <- vzdalenost / rychlost print(doba_jizdy) ``` Pokud jste svůj skript napsali do nového okna editoru v\ RStudiu, spustíte jej jednoduše stisknutím tlačítka `Source`. Výsledkem by mělo být, že pojedete necelých 12\ hodin. To byste mohli mnohem jednodušeji zjistit i\ s\ pomocí obyčejné kalkulačky. Skript vám však umožní zjistit i\ to, co se stane, pokud pojedete rychleji nebo pomaleji: stačí jen změnit rychlost na třetím řádku a skript spustit znovu. Podobně můžete změnit i\ vzdálenost na druhém řádku a zjistit, jak dlouho pojedete do jiné destinace. (V\ kapitole\ \@ref(kap:funkce) se naučíte proces, který vám umožní snadno měnit parametry výpočtu jako jsou rychlost a vzdálenost ještě více automatizovat pomocí tvorby vlastních funkcí.)