9 Elementi kontrole toka

Ovo poglavlje uvodi osnovne elemente kontrole toka u R-u, kao što su for i while petlje te uvjetne naredbe if, ifelse i switch. Ovi alati omogućuju nam uvjetno izvršavanje koda, ponavljanje radnji i fleksibilnu manipulaciju podacima temeljem zadatih uvjeta. Prikazani primjeri i primjene pokazuju kako kontrola toka može poboljšati učinkovitost i prilagodljivost analitičkog procesa u R-u.

U R-u, „for”, „if” i „ifelse” su temeljni elementi kontrole toka. Svaki od ovih elemenata ima svoju specifičnu ulogu i sintaksu:

For petlja:

  • „For” se koristi za izvođenje ponovljenih radnji unutar petlje.

  • Sintaksa:

    for (varijabla in skup) { # izvrši neku radnju }

  • Ovdje varijabla prolazi kroz svaki element u skup.

If uvjet:

  • „If” se koristi za ispitivanje uvjeta te izvršavanje koda ako je uvjet istinit (TRUE).

  • Sintaksa:

    if (uvjet) { # izvrši neku radnju }

  • Ovdje se radnja izvršava samo ako je uvjet istinit.

Ifelse funkcija:

  • „Ifelse” nije petlja, već vektorizirana funkcija koja omogućava ispitivanje uvjeta i vraća jednu vrijednost ako je uvjet istinit, a drugu vrijednost ako nije.

  • Sintaksa:

    ifelse(uvjet, vrijednost_za_true, vrijednost_za_false)

  • Ovdje funkcija vraća vrijednost_za_true ako je uvjet istinit, inače vraća vrijednost_za_false.

Svaki od ovih elemenata igra važnu ulogu u strukturiranju i kontroli toka programa u R-u. „For” petlja se koristi za iteracije, „if” uvjet za kontrolu toka na osnovi logičkih uvjeta, dok se „ifelse” često koristi za vektorizirane operacije koje zahtijevaju uvjetno izvršavanje.

9.1 for

Na primjer, recimo da želimo dobiti uvide u podatke o olujama. Podaci storms iz paketa dplyr sadrže informacije o putanjama oluja. To su podaci iz baze podataka Atlantskog uragana NOAA (Nacionalne uprave za oceane i atmosferu SAD), koji uključuju položaje i karakteristike oluja od 1975. do 2021. godine. Oluje od 1979. godine nadalje mjerene su svakih šest sati tijekom života oluje, dok su podaci za ranije godine ponekad nepotpuni.

Format podataka

Podaci su formatirani kao tibble (moderniji oblik podatkovnih okvira u R-u) s 19,066 opažanja i 13 varijabli:

  • name: ime oluje.

  • year, month, day: datum izvještaja. Godina, mjesec i dan su odvojene varijable koje zajedno čine datum.

  • hour: sat izvještaja (u UTC vremenu).

  • lat, long: lokacija središta oluje. Geografska širina i dužina.

  • status: klasifikacija oluje (tropska depresija, tropska oluja ili uragan).

  • category: kategorija uragana prema Saffir-Simpsonovoj skali, izračunata na temelju brzine vjetra.

    • NA: Nije uragan
    • 1: 64+ čvorova
    • 2: 83+ čvorova
    • 3: 96+ čvorova
    • 4: 113+ čvorova
    • 5: 137+ čvorova
  • wind: maksimalna održavana brzina vjetra oluje (u čvorovima).

  • pressure: zračni tlak u središtu oluje (u milibarima).

  • tropicalstorm_force_diameter: promjer (u nautičkim miljama) područja koje doživljava vjetrove snage tropske oluje (34 čvora ili više). Dostupno samo od 2004. godine.

  • hurricane_force_diameter: promjer (u nautičkim miljama) područja koje doživljava vjetrove snage uragana (64 čvora ili više). Dostupno samo od 2004. godine.

Na ovim podacima možemo isprobati nekolicinu primjera upotrebe kontrole toka. Prvo moramo učitati podatke.

> library(dplyr)
> data(storms)
> glimpse(storms)
## Rows: 19,537
## Columns: 13
## $ name                         <chr> "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "Amy", "A~
## $ year                         <dbl> 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1975, 1~
## $ month                        <dbl> 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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~
## $ day                          <int> 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 24, 24, 24, ~
## $ hour                         <dbl> 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 0, 6, 12, 18,~
## $ lat                          <dbl> 28, 28, 30, 30, 32, 32, 33, 34, 34, 34, 34, 34, 34, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 39, 40, 42, 44, 4~
## $ long                         <dbl> -79, -79, -79, -79, -79, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -70, -70, -69, -68, -67, -67, -66, -65, -64, -~
## $ status                       <fct> tropical depression, tropical depression, tropical depression, tropical depression, tropical depression, tropical depress~
## $ category                     <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ wind                         <int> 25, 25, 25, 25, 25, 25, 25, 30, 35, 40, 45, 50, 50, 55, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 55, 55, 55, 50, 50, 50, 4~
## $ pressure                     <int> 1013, 1013, 1013, 1013, 1012, 1012, 1011, 1006, 1004, 1002, 1000, 998, 998, 998, 987, 987, 984, 984, 984, 984, 984, 984, ~
## $ tropicalstorm_force_diameter <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ hurricane_force_diameter     <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~

for petlje se obično koriste za iterativno izvršavanje koda nad elementima nekog skupa, kao što su redovi ili stupci u datasetu. Evo nekoliko primjera kako možete koristiti for petlju s datasetom storms:

  • Ispisivanje vrijednosti

Možete koristiti for petlju da prođete kroz redove ili stupce dataset-a i ispišete određene vrijednosti. Na primjer, ispisati nazive svih oluja:

> for (i in 1:nrow(storms)) {
+   print(unique(storms$name[i]))
+ }

Ova petlja prolazi kroz svaki red u datasetu storms i ispisuje ime oluje. Ovdje je to zapisano kao komentar, jer bi u suprotnom rezultiralo ispisom 19066 redaka s nazivima oluja.

  • Izračunavanje i pohrana rezultata

Možete izračunati nešto za svaki red i pohraniti rezultate u novi vektor. Na primjer, izračunati maksimalnu brzinu vjetra za svaku godinu:

> # izdvajanje jedinstvenih godina
> unique_years <- unique(storms$year) 
> 
> # kreiranje praznog vektora u koji će se pohraniti najveće brzine vjetra, 
> # duljine vektora jedinstvenih godina
> max_wind_speed_per_year <- numeric(length(unique_years)) 
> 
> for (i in 1:length(unique_years)) {   
+   # i in 1:length(unique_years) funkcionira kao brojač 
+   # i redom prolazi kroz godine
+   year_data <- storms[storms$year == unique_years[i], ] 
+   # privremeni vektor (temp) u koji se pohranjuju podaci za promatranu godinu
+   max_wind_speed_per_year[i] <- max(year_data$wind, na.rm = TRUE) 
+   # utvrđivanje maksimalne vrijednosti za godinu i pohrana u 
+   # vektor max_wind_speed_per_year
+ }
> 
> summary(max_wind_speed_per_year)  
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##      80     115     125     128     145     165
> # vektor max_wind_speed_per_year i dalje ima puno (47) opažanja, 
> # pa će summary pružiti sažeti uvid u rezultate

Ukratko, ova petlja prolazi kroz svaku jedinstvenu godinu u datasetu i računa maksimalnu brzinu vjetra za tu godinu.

Na sličan način, može nas zanimati koliko je dugo svaka oluja trajala prema satima u kojima je zabilježena. Stoga, prethodni kod prilagođavamo s obzirom na predmet interesa.

> unique_names <- unique(storms$name) # izdvajanje jedinstvenih naziva
> max_hour <- numeric(length(unique_names)) # kreiranje praznog vektora 
> min_hour <- numeric(length(unique_names)) # kreiranje praznog vektora
> duration_hour <- numeric(length(unique_names)) # kreiranje praznog vektora
> 
> for (i in 1:length(unique_names)) {   
+   names_data <- storms[storms$name == unique_names[i], ] 
+   max_hour[i] <- max(names_data$hour, na.rm = TRUE) 
+   # utvrđivanje maksimalne vrijednosti
+   min_hour[i] <- min(names_data$hour, na.rm = TRUE) 
+   # utvrđivanje minimalne vrijednosti
+   duration_hour[i] <- max_hour[i]-min_hour[i]
+ }
> 
> storms_duration <- cbind.data.frame(unique_names, min_hour, 
+                                     max_hour, duration_hour)
> summary(storms_duration$duration_hour)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##      18      18      18      19      20      23

Napomene za korištenje for petlji u R-u

  • Iako su intuitivne i lako razumljive, for petlje u R-u su često manje efikasne od vektoriziranih operacija i funkcija poput apply(). Razmislite o korištenju vektoriziranih operacija gdje je to moguće za bolje performanse.
  • Prilikom rada s većim skupovima podataka, for petlje mogu biti sporije. U takvim slučajevima, paketi poput data.table ili dplyr mogu pružiti brže alternative.

9.2 apply, sapply, lapply

Da biste zamijenili for petlju apply funkcijom u R-u, trebate uzeti u obzir vrstu operacije koju izvodite. apply funkcije (koje uključuju apply, lapply, sapply, vapply itd.) omogućuju vektorizirane operacije na podatkovnim okvirima i listama.

  • Ispisivanje vrijednosti

Za ispisivanje imena oluja iz skupa podataka storms, možete koristiti lapply ili sapply. Međutim, ova operacija neće biti efikasnija s apply funkcijom jer je ispisivanje inherentno iterativni proces. Ali, za demonstraciju:

> sapply(storms$name, print)
  • Izračunavanje maksimalne brzine vjetra po godini

Ovo je složeniji primjer gdje apply funkcije uistinu mogu biti korisnije. Koristeći sapply ili lapply, možemo izračunati maksimalnu brzinu vjetra za svaku godinu:

> unique_years <- unique(storms$year)
> max_wind_speed_per_year <- sapply(unique_years, function(yr) {
+   max(storms$wind[storms$year == yr], na.rm = TRUE)
+ })
> 
> summary(max_wind_speed_per_year)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##      80     115     125     128     145     165

Ovdje sapply prolazi kroz svaku jedinstvenu godinu i primjenjuje funkciju koja računa maksimalnu brzinu vjetra za tu godinu. Rezultat je numerički vektor maksimalnih brzina vjetra za svaku godinu.

Napomene za korištenje apply funkcija:

  • apply funkcije su obično efikasnije od for petlji za vektorizirane operacije.
  • lapply vraća listu, dok sapply pokušava pojednostaviti rezultat u vektor ili matricu ako je to moguće.
  • Kod složenijih operacija ili kada su performanse kritične, alternativni pristupi kao što su funkcije iz paketa data.table mogu biti još efikasniji.

9.3 if

Primjena „if” uvjeta na skupu podataka poput storms iz paketa dplyr može se koristiti za različite analize i manipulacije podacima. Evo nekoliko primjera kako možete koristiti „if” uvjete sa skupom podataka storms:

  • Filtriranje i analiza

Možete koristiti „if” uvjete za filtriranje oluja na temelju određenih kriterija, kao što su kategorija, brzina vjetra ili godina. Na primjer, za ispitivanje je li neka oluja bila kategorije 4 ili veća. Prisjetimo se opisa podataka:

+ NA: Nije uragan
+ 1: 64+ čvorova
+ 2: 83+ čvorova
+ 3: 96+ čvorova
+ 4: 113+ čvorova
+ 5: 137+ čvorova

Dakle, kategorija 4 utvrđuje se temeljem jačine vjetra 113 čvorova ili više od toga. U ovom slučaju ne možemo izravno koristiti varijablu storms$category kao uvjet, zbog toga što sadrži NA. S obzirom da je if logički uvjet, ne može izvršiti provjeru vrijednosti koje nedostaju.

> for (i in 1:nrow(storms)) {
+   if (storms$wind[i] >= 113) {
+     print(paste(storms$name[i], "je bio uragan kategorije", storms$category[i]))
+   }
+ }

Ispis bi rezultirao podužim popisom, pa je zbog toga ovdje izuzet. No, možete sami isprobati ispis.

  • Izmjena u skupu podataka temeljem uvjeta

Možete dodati novi stupac u podatkovni skup na osnovi nekog uvjeta. Na primjer, označavanje oluje kao „Snažne” ili „Slabe” na temelju brzine vjetra (proizvoljno odabranih 100 čvorova):

> storms$intensity <- NA # kreiramo prazan stupac u skupu podataka
> 
> for (i in 1:nrow(storms)) {
+   if (storms$wind[i] >= 100) {
+     storms$intensity[i] <- "Snažna"
+   } else {
+     storms$intensity[i] <- "Slaba"
+   }
+ }
> 
> table(storms$intensity)
## 
##  Slaba Snažna 
##  18273   1264
  • Statistička analiza s uvjetima

Ovdje ćemo koristiti „if” uvjete za izračunavanje statističkih podataka, kao što su prosječne vrijednosti, ali samo za određene oluje. Na primjer, izračunajmo prosječni tlak za oluje kategorije 5:

> kat_5_tlak <- numeric()
> 
> for (i in 1:nrow(storms)) {
+   if (storms$wind[i] >= 137) {
+     kat_5_tlak <- c(kat_5_tlak, storms$pressure[i]) 
+   }
+ }
> print(paste("Oluje kategorije 5, prosječno dosežu ", 
+             mean(kat_5_tlak, na.rm = TRUE), 
+             "milibara tlaka zraka u središtu"))
## [1] "Oluje kategorije 5, prosjecno dosežu  918.172413793103 milibara tlaka zraka u središtu"

Napomena: dok „if” uvjeti mogu biti korisni za iterativno pregledavanje i manipulaciju redaka podatkovnog okvira, vektorizirane funkcije u R-u često nude efikasnija i čišća rješenja za ovakve operacije. Na primjer, dplyr funkcije kao što su filter(), mutate() i summarise() mogu obaviti slične zadatke bez potrebe za eksplicitnom petljom.

9.4 ifelse

Za korištenje if uvjeta bez for petlje na skupu podataka storms, možete se osloniti na vektorizirane funkcije poput ifelse. ifelse je vrlo koristan za primjenu uvjeta na cijeli vektor ili stupac u podatkovnom okviru.

  • Klasifikacija

Pretpostavimo da želite klasificirati oluje kao „Snažne” ili „Slabe” (kao u ranijem primjeru) na temelju njihove maksimalne brzine vjetra. U ovom slučaju, možete koristiti ifelse da dodate novi stupac u podatkovni okvir:

> storms$intensity <- NA
> 
> storms <- storms %>%
+   mutate(intensity = ifelse(wind >= 100, "Snažna oluja", "Slaba oluja"))
> 
> table(storms$intensity)
## 
##  Slaba oluja Snažna oluja 
##        18273         1264

ifelse testira uvjet \(wind \geq 100\) za svaki red u skupu podataka storms. Ako je uvjet istinit, dodjeljuje vrijednost „Snažna oluja” novom stupcu intensity. Ako uvjet nije istinit, dodjeljuje „Slaba oluja”.

  • Filtriranje podataka

Također, možete koristiti kombinaciju ifelse i filter za filtriranje podataka na temelju određenog uvjeta. Na primjer, izdvajanje podataka samo za uragane kategorije 5:

> category_5_storms <- filter(storms, wind >= 137)
> 
> glimpse(category_5_storms)
## Rows: 116
## Columns: 14
## $ name                         <chr> "Anita", "Anita", "David", "David", "David", "David", "David", "David", "David", "Allen", "Allen", "Allen", "Allen", "All~
## $ year                         <dbl> 1977, 1977, 1979, 1979, 1979, 1979, 1979, 1979, 1979, 1980, 1980, 1980, 1980, 1980, 1980, 1980, 1980, 1980, 1980, 1980, 1~
## $ month                        <dbl> 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 1~
## $ day                          <int> 2, 2, 30, 30, 30, 31, 31, 31, 31, 5, 5, 5, 5, 6, 7, 7, 7, 8, 9, 9, 9, 13, 14, 14, 14, 14, 15, 23, 23, 23, 24, 24, 26, 26,~
## $ hour                         <dbl> 0, 6, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 0, 6, 12, 18, 0, 6, 12, 15, 18, 12, 18, 21, 8, 9, 12, 18, 0~
## $ lat                          <dbl> 25, 24, 16, 16, 17, 17, 17, 17, 18, 15, 15, 16, 16, 18, 20, 21, 22, 22, 24, 25, 25, 19, 20, 20, 20, 21, 15, 25, 25, 25, 2~
## $ long                         <dbl> -96, -97, -64, -65, -66, -67, -68, -69, -70, -67, -69, -70, -72, -74, -84, -85, -86, -88, -93, -94, -95, -82, -84, -85, -~
## $ status                       <fct> hurricane, hurricane, hurricane, hurricane, hurricane, hurricane, hurricane, hurricane, hurricane, hurricane, hurricane, ~
## $ category                     <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5~
## $ wind                         <int> 140, 150, 140, 145, 150, 145, 145, 145, 150, 140, 145, 155, 150, 140, 145, 155, 165, 155, 145, 155, 140, 140, 160, 155, 1~
## $ pressure                     <int> 931, 926, 925, 924, 924, 927, 928, 927, 926, 911, 916, 932, 940, 945, 935, 910, 899, 920, 912, 909, 916, 905, 888, 889, 8~
## $ tropicalstorm_force_diameter <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ hurricane_force_diameter     <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
## $ intensity                    <chr> "Snažna oluja", "Snažna oluja", "Snažna oluja", "Snažna oluja", "Snažna oluja", "Snažna oluja", "Snažna oluja", "Snažna o~

Ovdje filter funkcija iz dplyr paketa omogućuje filtriranje redaka u podatkovnom okviru storms, s obzirom na uvjet da je vrijednost stupca wind veća ili jednaka 137.

Iako se može činiti da se skup podataka i podatkovni okvir koriste naizmjenično kao sinonimi, to nije tako. Ponovimo kratko njihova značenja. Skup podataka (engl. dataset) je pojam koji se koristi za označavanje bilo kojeg skupa prikupljenih podataka, neovisno o vrsti i načinu pohrane. To mogu biti skupovi pojedinačnih opažanja, dokumenata, slika, tablica, baza podataka itd. Nadalje, skupovi podataka mogu se pohraniti u različitim formatima kao što su csv datoteke, Excel tablice, SQL baze podataka i slično. Podatkovni okvir (engl. dataframe) je specifičan pojam koji se najčešće koristi u kontekstu programskih jezika za statističku analizu i manipulaciju podacima, poput R i Python (posebno uz biblioteku pandas). Podatkovni okvir predstavlja tabličnu strukturu podataka s redovima i stupcima, gdje reci predstavljaju pojedinačne zapise (primjere, mjerenja, itd.), a stupci predstavljaju varijable (atribute, značajke). Na primjer, ako bismo na raspolaganju imali podatkovni okvir rezultata anketiranja, pojedini redak sadržavao bi odgovore jednog ispitanika, dok bi pojedini stupac sadržavao odgovore na pojedino pitanje. Ova struktura omogućava lakšu manipulaciju, analizu i vizualizaciju podataka. Dakle, podatkovni okvir je ujedno i skup podataka, ali neće svaki skup podataka ujedno biti i podatkovni okvir.

9.5 Razlika između ifelse i kombinecije if i else

Razlike između ifelse funkcije i kombinacije if i else izraza u R-u leže u načinu kako oni pristupaju uvjetnom izvršavanju koda, njihovoj vektorizaciji, i u situacijama u kojima se obično koriste.

ifelse je vektorizirana funkcija koja omogućava provjeru uvjeta nad cijelim vektorom elemenata odjednom i vraća vektor rezultata temeljem tog uvjeta. Sintaksa:

> ifelse(test, da, ne)
  • test: logički vektor koji sadrži uvjet koji se provjerava za svaki element,
  • da: vrijednost koja se vraća ako je uvjet istinit,
  • ne: vrijednost koja se vraća ako je uvjet neistinit.

Primjer: Zamislimo da imamo vektor temperatura i želimo označiti sve temperature iznad 25 stupnjeva kao „Toplo”, a manje ili jednake 25 kao „Ugodno”.

> temperature <- c(22, 28, 25, 30, 18)
> vrijeme <- ifelse(temperature > 25, "Toplo", "Ugodno")
> print(vrijeme)
## [1] "Ugodno" "Toplo"  "Ugodno" "Toplo"  "Ugodno"

if i else izrazi koriste se za uvjetno izvršavanje koda temeljem ispunjenja nekog uvjeta. Za razliku od ifelse, if i else se ne mogu direktno primijeniti na vektore, već evaluiraju samo prvi element logičkog vektora ako im se takav prosljedi. Sintaksa:

> if (uvjet) {
+   # izvršava se ako je uvjet istinit
+ } else {
+   # izvršava se ako uvjet nije istinit
+ }

Primjer: Uzmimo isti scenarij s temperaturama, ali primijenimo if i else za provjeru pojedinog elementa.

> temperatura <- 28
> if (temperatura > 25) {
+   vrijeme <- "Toplo"
+ } else {
+   vrijeme <- "Ugodno"
+ }
> print(vrijeme)
## [1] "Toplo"

Za vektoriziranu provjeru, morali bismo koristiti petlju ili neku vrstu aplikacijske funkcije (npr., lapply) ili kombinaciju s for petljom.

Ključne razlike

  1. Vektorizacija: ifelse može obraditi cijele vektore odjednom, automatski primjenjujući uvjet na svaki element i vraćajući vektor rezultata. Kombinacija if i else može evaluirati samo pojedinačne elemente ili se mora koristiti unutar petlje za iteraciju kroz vektore.

  2. Performanse: ifelse je obično brži za vektorizirane operacije jer je specifično dizajniran za takve zadatke. if i else mogu biti korisni za kontrolu toka unutar funkcija ili skripti gdje evaluacija pojedinačnih uvjeta ima smisla.

  3. Složenost: Za složenije uvjetne strukture s više grana, if i else pružaju veću fleksibilnost i čitljivost. ifelse je praktičan za jednostavne, brze provjere i zamjene u vektorima.

Ovisno o zadatku, odabrat ćete ifelse za vektorizirane operacije i jednostavne zamjene, ili if i else za složeniju logiku kontrole toka gdje je potrebna evaluacija pojedinačnih uvjeta ili gdje se koriste složenije strukture odlučivanja.

9.6 switch

switch izraz omogućava jednostavno grananje izvršavanja koda temeljem vrijednosti nekog izraza. Ovo je posebno korisno kada imate višestruke uvjete koje želite testirati protiv jedne varijable. switch može smanjiti potrebu za složenim if-else if lancima, čineći kod čišćim i lakšim za čitanje. Sintaksa:

switch(izraz, slučaj1 = vrijednost1, slučaj2 = vrijednost2, …, slučajN = vrijednostN)

gdje je izraz varijabla čiju vrijednost uspoređujete, a slučajX su moguće vrijednosti te varijable. Ako se vrijednost izraza podudara s nekim od slučajeva, izvršit će se zadani kod za prepoznati slučaj.

Primjer: Zamislimo aplikaciju za praćenje vremena putem koje želimo korisnicima prikazati poruku temeljenu na trenutnoj sezoni.

> trenutna_sezona <- "ljeto"
> 
> poruka <- switch(trenutna_sezona,
+                  proljece = "Vrijeme je za sadnju cvijeća!",
+                  ljeto = "Vrijeme je za plažu i sunčanje!",
+                  jesen = "Vrijeme je za berbu i promatranje boja lišća!",
+                  zima = "Vrijeme je za skijanje i uživanje u snijegu!",
+                  "Nepoznata sezona")  
>                  # Zadnji slučaj je „Nepoznata sezona" ako se izraz 
>                  # ne podudara ni s jednim slučajem
> 
> print(poruka)
## [1] "Vrijeme je za plažu i suncanje!"

Ovaj kod postavlja varijablu trenutna_sezona na „ljeto” i koristi switch za odabir odgovarajuće poruke. Budući da je trenutna_sezona postavljena na „ljeto”, ispisat će se: „Vrijeme je za plažu i sunčanje!“.

Prednosti korištenja switcha:

  • Smanjuje potrebu za dugim if-else if lancima, čineći kod preglednijim i lakšim za održavanje.
  • Olakšava upravljanje višestrukim grananjima izvršavanja temeljenim na jednoj varijabli.
  • Pomaže u očuvanju performansi koda u scenarijima s mnogo uvjeta.

U praksi, switch se često koristi kada imate unaprijed zadan skup mogućih vrijednosti za varijablu i želite izvršiti različite radnje za svaku od tih vrijednosti. To ga čini idealnim alatom za situacije poput obrade korisničkih unosa, odabira konfiguracijskih opcija, upravljanja stanjima u aplikaciji i slično.

9.7 while

while petlja se koristi za ponavljanje izvođenja bloka koda dok god je određeni uvjet zadovoljen. Za razliku od for petlje, koja prolazi kroz fiksni skup elemenata, while petlja može se koristiti kada unaprijed ne znamo koliko puta će biti potrebno izvršiti radnju. Sintaksa:

> while (uvjet) {
+   # kod koji se izvršava dok je uvjet istinit
+ }

U ovom kontekstu, uvjet je logički izraz. Ako je uvjet istinit (TRUE), kod unutar petlje se izvršava. Nakon svake provedbe, uvjet se ponovno provjerava. Petlja se nastavlja sve dok je uvjet istinit. Ako uvjet postane neistinit (FALSE), izvršavanje petlje se prekida.

Primjer: Pretpostavimo da želimo izračunati faktorijel broja. Faktorijel broja n (označeno s n!) je umnožak svih pozitivnih cijelih brojeva manjih ili jednakih n. Na primjer, \(5! = 5 × 4 × 3 × 2 × 1\)

> broj <- 5
> faktorijel <- 1  # Početna vrijednost faktorijela
> 
> while (broj > 0) {
+   faktorijel <- faktorijel * broj  
+   # Množi trenutnu vrijednost faktorijela s trenutnim brojem
+   broj <- broj - 1  # Smanjuje broj za 1
+ }
> 
> print(faktorijel)
## [1] 120

U ovom primjeru, while petlja se koristi za izračun faktorijala broja 5. Petlja počinje s brojem 5 i množi trenutnu vrijednost faktorijala s trenutnim brojem sve dok broj ne postane 0.

Prednosti korištenja while petlje:

  • Fleksibilnost u izvođenju koda bez prethodnog znanja o broju iteracija.
  • Korisna je za situacije kad izvršavanje ovisi o vanjskim uvjetima ili promjenjivim stanjima.

Bitno je pripaziti da uvjet u while petlji u nekom trenutku postane neistinit, inače može dovesti do beskonačne petlje koja može „zamrznuti” ili ozbiljno usporiti izvršavanje programa. Uvijek osigurajte da postoji mehanizam za prekid petlje kako bi se izbjegle potencijalne beskonačne iteracije.

Pitanja za ponavljanje

  1. Koja je svrha for petlje u R-u, i kako biste je koristili za ispisivanje imena svih oluja iz skupa podataka storms?

  2. Kako koristiti if uvjet za provjeru je li brzina vjetra veća od 100 čvorova i dodati oznaku „Snažna oluja” ili „Slaba oluja” za svaku oluju u storms podatkovnom okviru?

  3. Koja je razlika između if uvjeta i ifelse funkcije u R-u, te kada biste koristili jednu, a kada drugu?

  4. Objasnite kako ifelse može pojednostaviti klasifikaciju podataka u podatkovnom okviru. Prikažite primjer klasifikacije oluja u storms podatkovnom okviru na temelju brzine vjetra.

  5. Što radi apply funkcija i u kojim situacijama je ona efikasnija od for petlje?

  6. Kako biste primijenili switch izraz za odabir različitih poruka koje se prikazuju ovisno o sezoni („proljeće”, „ljeto”, „jesen”, „zima”)?

  7. Objasnite kada biste koristili while petlju umjesto for petlje i navedite primjer za izračun faktorijela broja pomoću while petlje.

  8. Kako koristiti lapply funkciju za primjenu operacije na svakom elementu liste u R-u? Dajte primjer u kojem lapply računa kvadrate brojeva u listi.

  9. Koje su najčešće greške pri korištenju while petlje, i kako ih izbjeći?

  10. Zašto je važno osigurati kraj petlje (npr. u while petlji), i kako biste mogli provjeriti ili izbjeći beskonačnu petlju u R-u?