Slovník | Vyhledávání | Mapa webu
 
Základy informatiky pro biologyCvičebnice jazyka R 6. cvičení – Podmíněné příkazy a cykly v R

6. cvičení – Podmíněné příkazy a cykly v R

Podmíněné příkazy a cykly v R

Cíle 6. cvičení: V rámci 6. kapitoly si vysvětlíme základní práci s podmínkami a cykly v jazyce R, tj. naučíme se definice a správné využití podmíněných příkazů / cyklů.


Podmíněné příkazy

Potřebujeme-li v jazyce R vyhodnotit příkaz (případně jejich sérii) na základě výsledku alespoň jedné podmínky, využije struktury tzv. podmíněných příkazů. Podmíněné příkazy většinou přicházejí na řadu tehdy, když jednoduché příkazy nebo jejich posloupnosti ohraničené složenými závorkami již k řešení samy o sobě nevedou.

Základním příkazem pro vytvoření podmínky je tzv. if klauzule. Vždy je uvedena klíčovým slovem if, za kterým následuje v kulatých závorkách definovaná podmínka následovaná ve složených závorkách uzavřenými příkazy, které se provádějí, je-li podmínka splněna. Její základní strukturu tedy tvoří tato logika

if (logická podmínka) {příkazy vyhodnocující se při splnění dané podmínky}

Splnění dané podmínky znamená, že její návratová hodnota je TRUE. Pokud je výsledkem podmínky FALSE, příkazy ve složených závorkách nejsou provedeny.
Začněmě ukázkou jednoduché podmínky, definujme x = 10, v případě, že je hodnota x > 0, bude konzole vracet text "Číslo je kladné."

x <- 10
if (x > 0) {"Číslo je kladné"}

Vzhledem k tomu, že vektor x obsahuje hodnotu 10, byla podmínka vyhodnocena jako TRUE a konzole vrátila oznámení "Číslo je kladné". Pokud do vektoru x vložíme hodnotu zápornou, bude podmínka vyhodnocena jako FALSE a neprovede se žádný příkaz. Složené závorky {}, do kterých definujeme příkazy, nejsou v rámci takto jednoduchého kódu povinné, ale pro zachování přehlednosti skriptu jsou silně doporučovány.

Pokud podmínka vrací jako výsledek logický vektor o více hodnotách, je pro její vyhodnocení brán v potaz pouze první prvek tohoto vektoru. O této skutečnosti nás informuje varovná hláška přímo v konzoli.

x <- c(-5, -2, 0, 2, 4, 6)
if (x > 0) {"Číslo je kladné"}

Součástí podmíněného příkazu if je ale také nepovinný parametr else, za který můžeme definovat příkazy, které se provedou v případě, že podmínka je vyhodnocena jako FALSE.

x <- 10
if (x > 0) {"Číslo je kladné"
} else {"Číslo je záporné nebo nula"}

Při využití větvení pomocí else je vhodné psát pravou složenou závorku bezprostředně před else - protože else část příkazu nepovinná, kompilátor často vyhodnotí případný prázdný řádek jako ukončení předchozího if příkazu.
Stejného výsledku jako v příkladu výše dosáhneme také využitím funkce ifelse(), jehož základní struktura obsahuje podmínku a dvě série příkazů (při splnění / nesplnění podmínky):

ifelse(podmínka, příkazy pokud podmínka = TRUE, příkazy pokud podmínka = FALSE)

Pokud se tedy vrátíme k příkladu výše, můžeme jej přepsat jako

ifelse(x > 0, "Číslo je kladné", "Číslo je záporné nebo nula")

Tento příkaz je také vhodný pro práci s podmínkou, jejímž výsledkem je logický vektor.

x <- c(-5, -2, 0, 2, 4, 6)
ifelse(x > 0, "Číslo je kladné", "Číslo je záporné nebo nula")

Podmíněné příkazy můžeme samozřejmě vnořovat do sebe a dosáhnout tak i složitějších rozhodovacích struktur. Tohoto vnoření dosáhneme vepsáním nové if struktury bezprostředně za else v podmínce předchozí:

x <- 10
if (x > 0) {"Číslo je kladné"
} else if (x == 0) {"Číslo je rovno nule"
} else {"Číslo je záporné"}

Mezi podmíněné příkazy řadíme dále také funkci switch(), která po vyhodnocení výrazu, který je jejím prvním argumentem, vrací jeden ze svých dalších argumentů:

switch(vyraz, "argument1", "argument2", "argument3", "argument4")

Pokud je výrazem celé číslo, vrací konzole argument, který je v odpovídajícím pořadí. Nenajde-li funkce odpovídající argument, vypíše konzole NULL. Je-li výrazem text, musí být i argumenty kódovány pomocí textových řetězců; u textových řetězců jde také definovat libovolný text, který je vypsán v případě, že výraz na vstupu není mezi argumenty.

switch(2, "jednička", "dvojka", "trojka", "čtyřka", "pětka")
switch("B", A = "1", B = "1-", C = "2", D = "2-", E = "3", F = "neprospěl")
switch("G", A = "1", B = "1-", C = "2", D = "2-", E = "3", F = "neprospěl", "mimo stupnici")


Cykly

V případě nutnosti opakovaného vyhodnocení našich příkazů či jejich skupin můžeme využít tzv. cykly. Pokud víme, kolikrát chceme naše příkazy opakovat, využíváme nejčastěji příkaz for. Nevíme-li, kolikrát budeme příkazy opakovat (tj. počet opakování závisí na splnění nějaké podmínky), máme k dispozici cykly while a repeat. Vždy je potřeba řádně definovat konec cyklu, aby nedošlo k zacyklení.

For cyklus

for (indexační_proměnná in výraz) {příkazy vyhodnocující se při každém průchodu cyklem}

Výraz může být definován jako vektor nebo seznam, pro každou složku tohoto výrazu je pak náš cyklus vyhodnocen (=jsou provedeny všechny příkazy uvedené ve složených závorkách jako oddělovač příkazů využíváme středník). Indexační proměnnou lze upravovat v rámci cyklu, cyklus není ovlivněn. Indexování je možné začít i od 0, příkaz bude vyhodnocen, index 0 ale nebude dosazen, neboť v jazyce R (narozdíl například od jazyka Python) v rámci žádného objektu neexistuje nultý prvek. Uveďme pro začátek jednoduchý příklad, kdy chceme vypsat aktuální hodnotu indexační proměnné vynásobenou a vydělenou 10, příkaz chceme provést 10krát.

for (i in 1:10) {print(10*i); print(i/10)}

Sekvenci, která by nám definovala indexační proměnnou, můžeme definovat přímo v rámci cyklu (příklad výše) nebo můžeme využít již dříve zadefinované proměnné. Častým případem je také situace, kdy chceme iterovat přes všechny prvky vektoru, u kterého neznáme délku. Zde se nabízí využití funkce length pro definování nejvyšší hodnoty opakování cyklu, pokud však může nastat situace, kdy délka vektoru může být nulová, je vhodné využít příkaz seq_along() (viz nápověda funkce seq), který v případě nulové délky objektu vrátí prázdný vektor a iterace se neprovede. Tentýž příkaz využíváme i pro iterace s negativními čísly.

vysledek <- c() # výsledek cyklu budeme ukládat do vektoru "vysledek", nejprve je třeba jej definovat jako prázdný vektor
iterace <- 1:10 # sekvenci pro definici iterační promnné uvedeme mimo for cyklus
for (i in iterace) {vysledek[i] <- 10*i}
vysledek

vysledek <- c() # vektor s výsledkem předchozího cyklu vrátíme do původní podoby
for (i in 1:iterace) {vysledek[i] <- 10*i} # špatná definice - "iterace" je vektor nikoliv pouze 1 číslo
vysledek # příkaz je vyhodnocen, ale cyklus se provede jen 1krát
vysledek <- c() # vektor s výsledkem předchozího cyklu vrátíme do původní podoby
for (i in 1:length(iterace)) {vysledek[i] <- 10*i} # definici upravíme pomocí funkce length()
vysledek

vysledek <- c() # vektor s výsledkem předchozího cyklu vrátíme do původní podoby
iterace <- seq(-1, -10, -1) # nyní naše iterace obsahuje záporná čísla
for (i in iterace) {vysledek[i] <- 10*i}
vysledek # iteraci lze provést, ale není možné přes ni indexovat, výsledkem je tedy stále prázdný vektor
for (i in iterace) {vysledek <- c(vysledek, 10*i)} # indexaci prvků ve výsledném vektoru tedy musíme buď obejít
vysledek

vysledek <- c() # vektor s výsledkem předchozího cyklu vrátíme do původní podoby
for (i in seq_along(iterace)) {vysledek[i] <- 10*iterace[i]} # nebo můžeme využít funkce seq_along()
vysledek

While cyklus

while (logická podmínka) {příkazy vyhodnocující se při splnění dané podmínky}

Struktura příkazu je velmi podobná podmínce if probírané v úvodu tohoto cvičení. Příkazy jsou cyklicky provedeny pokaždé, když vyhodnocení logické podmínky vrátí hodnotu TRUE. Uveďme si jednoduchý příklad jako u for cyklu, pro přehlednost rozepíšeme celý příkaz strukturovaně na více řádků.

i <- 1
while (i < 11) { # nejprve stanovíme podmínku, pro kterou se bude cyklus provádět
print(10*i) # výstup našeho cyklu
i <- i + 1 # zvýšení indexační proměnné, tato proměnná je při dalším průchodu cyklem opět nejprve vyhodnocena v rámci podmínky v ()
}

Repeat cyklus

repeat {příkazy vyhodnocující se do konce, ten je definován pomocí {break}}

Tento cyklus je velmi podobný vše uvedenému while cyklu - opět opakuje vyhodnocování příkazů, příkazy provádí dokud nedosáhne konce. Konec definujeme vni cyklu pomocí příkazu break.

i <- 1
repeat {
print(10*i) # výstup našeho cyklu
i <- i + 1 # zvýšení indexační proměnné
if (i > 10) {break} # stanovení konce příkazu
}


Cvičení

Nejprve výše uvedené cykly procvičíme pomocí jednoduchých zejména matematických úloh:

1. Pomocí for cyklu spočtěte součet přirozených čísel od 1 do 1 000.

2. Napište podmíněný příkaz, který ověří, že zadané číslo je dělitelné 13 beze zbytku. (nápověda: pro výpočet zbytku po dělení využijte příkaz %%)

3. S využitím cyklu while a podmínky if vypište všechny mocniny 4 menší než 100 000.

4. Napište podmíněný příkaz, který ověří, že tři vstupy a, b a c splňují trojúhelníkovou nerovnost.

5. Pomocí for cyklu spočtěte faktoriál libovolného čísla.

6. Pomocí kombinace for cyklu a podmíněného příkazu zjistěte, kolik samohlásek / číslic obsahuje libovolný 5 znaků dlouhý řetězec.

Pro zbytek cvičení si stáhněte soubor pacienti.xlsx, který popisuje 88 pacientů, u kterých byly sesbírány bazální informace o zdravotním stavu před a po operaci. Uložte soubor na disk do složky, ve které budete i nadále pracovat, a nastavte tuto složku jako pracovní.

7. U řádně vyplněných záznamů (tj. bez chybějících obou hodnot) spočtěte rozdíl tepové frekvence před a po operaci (proměnné tep_pred, tep_po).

8. Vytvořte novou proměnnou hemoglobin_kat, kde shrňte, zda uvedené hodnoty hemoglobinu (sloupec hemoglobin) jsou v normě / pod normou / nad normou. Norma: muži 132–173 g/l, ženy 117–155 g/l.

9. Zkontrolujte, zda je možné všechny hodnoty v proměnné vaha považovat za validní. Nevalidní hodnoty odstrańte.

10. Spočtěte délku sledování jako rozdíl poslední (posledni_kontrola) a první kontroly (prvni_kontrola). Výpočet proveďte 2 způsoby - pomocí while cyklu i if podmínky - a vždy zkontrolujte, že délku hospitalizace počítáte opravdu jen pro chronologicky správně vyplněná data.

11. Vytvořte sloupec kontrola, jedničkou v tomto sloupci pomocí for cyklu označte každého pátého pacienta.

 
vytvořil Institut biostatistiky a analýz Lékařské fakulty Masarykovy univerzity