2 Osnovni tipovi podataka i operatori


“Osnovni” ili “primitivni” tipovi podataka su temeljni izgradbeni blokovi programskih jezika. Ovdje se najčešće misli na ugrađene mehanizme koji omogućuju pohrane elementarne informacije - najčešće logičkog, numeričkog ili znakovnog tipa. Većina programskih jezika koristi iste ili vrlo slične načine pohrane takvih informacija, što znači da implementira slične osnovne tipove podataka - razlika je često u detaljima kao što su odabrani nazivu tipa, nazivni broj bajtova i sl. U svakom slučaju najčešći prvi korak kod učenja novog programskog jezika jest upoznavanje osnovnih tipova podataka koje isti podržava.

Sljedeća stvar koja nas potom može zanimati jest sintaksa jezika, tj. način na kojeg pišemo naredbe koje interpreter jezika može razumjeti i izvršiti. Jezik R u svojoj sintaksi slijedi slične konvencije viđene u jezicima kao što su Python, Ruby ili Java, naravno uz određene specifičnosti (kao i svaki pojedini programski jezik). Neka osnovna sintaksna pravila su: svaka naredba u pravilu mora ići u svoj redak, ali uvlačenje naredbi nije bitno kao ni stavljanje točke-zareza na kraj naredbe; blokove definiramo vitičastim zagradama; tipove varijabli ne moramo definirati unaprijed već se oni samo prilagođavaju pridruženoj vrijednosti; komentari započinju znakom #; i sl. Sintaksu ćemo najbolje naučiti kroz primjere - učenjem elemenata jezika sintaksna pravila često postaju intuitivno jasna. Najbolje je krenuti sa jednostavnim funkcijama i operatorima, što ćemo i učiniti u ovoj lekciji.

Lekciju ćemo završiti raspravom o tzv. “nedostajućim” ili “nepostojećim” vrijednostima. Budući da R ima svoj vlastiti način definiranja takve vrste vrijednosti, odmah ćemo pojasniti način na koji su one u R-u implementirane kako bi u lekcijama koje slijede bili pripremljeni za lako upravljanje takvim vrijednostima (koje se vrlo često susreću u radu sa stvarnim podatkovnim skupovima).


2.1 Osnovni tipovi podataka

R poznaje šest osnovnih tipova podataka:

tip izvorni naziv tipa primjeri
logički logical TRUE, FALSE ili T, F
cjelobrojni integer 2L, 5L, 123456789L
realni double 4, 6, 3.14, 2e5
kompleksni complex 5 + 2i, 7 + 1i
znakovni character "A", "B", "Pero", "ABCDEFGHijklmnoPQRSTUVwyz"
bajtovi raw as.raw(2), charToRaw("1")

Neke opaske:

  • cjelobrojni i realni tipovi se često zajedno tretiraju kao tip numeric (iako ovo nije u potpunosti konzistentno!)
  • kompleksni tip mora imati deklariranu imaginarnu konstantu čak i ako je ona 1 (2 + i nije dobar zapis!)
  • tip “sirovih” bajtova se relativno rijetko koristi

Provjeru da li je neka varijabla određenog tipa možemo raditi uz pomoć funkcije is.<naziv_tipa>. Ovo ćemo isprobati u sljedećem zadatku. Prije nego što počnemo s rješavanjem uvedimo jedan novitet: u zadacima gdje ispisujemo više stvari na zaslon korisno je vizualno odvojiti različite segmente ispisa kako bismo lakše shvatili na koji dio koda se referenciraju. U tu svrhu ćemo koristiti naredbu cat("-----------\n") koja jednostavno na zaslon ispisuje niz crtica i prelazi u novi red. Mogli smo koristiti i funkciju print(), no ona uvijek započinje ispis sa indeksom elementa dok naredba cat predstavlja “sirovi” ispis, što nam u ovom slučaju više odgovara.


Zadatak 2.1 - provjera tipova podataka

## [1] TRUE
## [1] TRUE
## [1] TRUE
## -----------
## [1] TRUE
## [1] TRUE
## [1] TRUE
## [1] TRUE
## [1] FALSE

Da li ste uočili nešto neobično u ovim provjerama? Pokušajte objasniti dobiveni rezultat.

Tip neke varijable ili konstante možemo dohvatiti uz pomoć funkcija typeof ili class. Razlika između njih je sljedeća:

  • typeof - dohvaća “primitivni” ili “osnovni” tip podatka (integer, double )
  • class - “objektni tip”, zapravo vrijednost atributa class

Zadatak 2.2 - dohvat naziva tipa podatka

## [1] "logical"
## [1] "integer"
## [1] "logical"
## [1] "double"
## [1] "character"
## -----------
## [1] "logical"
## [1] "integer"
## [1] "logical"
## [1] "numeric"
## [1] "character"

Podatke možemo eksplicitno pretvarati iz jednog tipa u drugi uz pomoć funkcije as.<naziv_tipa>:


Zadatak 2.3 - pretvorba tipova podataka

## [1] 2
## [1] 1
## [1] "100"
## [1] "2.35"
## [1] "200"
## [1] FALSE
## [1] TRUE

R će sam provoditi implicitnu pretvorbu ukoliko je moguća:


Zadatak 2.4 - implicitna pretvorba


Implicitna pretvorba će se izvesti samo ako je smislen - npr. aritmetički operator između znakovne i numeričke varijable rezultirati će greškom.


2.2 Operatori

Kao i u drugim programskim jezicima, R dozvoljava korištenje operatora u izrazima. Neki od češće korištenih operatora su:

  • aritmetički +, -, *, /, ** (potencija), %% (modulo), %/% (cjelobrojno dijeljenje)
  • usporedni <, <=, >, >=, ==, !=
  • logički ! (negacija), && (skalarni “i”), || (skalarni “ili”), & (vektorski “i”), | (vektorski “ili”)
  • pridruživanje <- ili =

Zadatak 2.5 - operatori


Logičke vrijednosti i usporedne operatore najčešće ćemo koristiti kod tzv. “uvjetnog izvođenja naredbi”, poznatog iz drugih programskih jezika kao “IF ELSE” naredba. U R-u njezina sintaksa izgleda ovako:

if (izraz) {blok} else {blok}

Isprobajmo ovu naredbu na sljedećem zadatku:


Zadatak 2.6 - uvjetno izvođenje naredbi


Uočili smo gore da imamo dvije vrste logičkih operatora za “i” i “ili”. Razliku ćemo objasniti kasnije, za sada je dovoljno reći da se kod uvjetnog izvođenja naredbi ili programskih petlji gotovo isključivo koristimo operatorima && i || (“C++ - ovski” operatori!).

Isto tako, već smo spomenuli da R nudi dva operatora pridruživanja, <- i =. Između njih postoje neke sitne razlike, no one nemaju gotovo nikakav utjecaj na uobičajeno korištenje ovog operatora u praksi. U literaturi se za pridruživanje vrijednosti novim varijablama može vidjeti i jedna i druga inačica, no mi ćemo u nastavku primarno i konzistentno koristiti <-, ponajviše zato kako bi programski kod bio vizualno distinktivniji od drugih programskih jezika.

NAPOMENA: za jednostavniji upis operatora <- možemo se koristiti kombinacijom tipaka ALT i -

Kod pridruživanja pazimo da je s lijeve strane tzv. “lijeva vrijednost” (engl. lvalue). Ovo u programerskom smislu interpretiramo kao “nešto u što se može pohraniti izračunata vrijednost”.

U pravilu se u R-u kao lvalue koristi varijabla, iako se tu ponekad može pojaviti i poziv funkcije. Ovu možda inicijalno zbunjujuću pojavu razjasniti ćemo kasnije.


Imenovanje varijabli uglavnom slijedi pravila iz drugih programskih jezika - dozvoljena su slova, brojke, podcrta ali i točka . Prvi simbol mora biti slovo ili točka.

U praksi za varijable složenih imena trebamo odabrati jednu od sljedećih konvencija:

Bitno je da u programskom kodu ne miješamo konvencije tj. da nakon odabira budemo konzistentni.

Ukoliko baš inzistiramo na čudnim imenima koja koriste specijalne znakove, onda ih moramo staviti pod tzv. “lijeve jednostruke apostrofe” (engl. backticks):


Zadatak 2.7 - ime varijable sa specijalnim znakovima

Ovakav način imenovanja varijabli nije previše koristan u praksi, ali ima i svoju svrhu - budući da su operatori u R-u zapravo funkcije (čija su imena doslovno +, ** i sl.) upotrebom lijevih apostrofa možemo ih direktno referencirati u njihovom originalnom obliku, što se može pokazati vrlo praktičnim kod tzv. funkcijskog programiranja (o čemu ćemo govoriti u jednoj od budućih lekcija).


Pridjeljivanje vrijednosti novim nazivima varijabli mi zapravo stvaramo nove varijable u radnoj okolini (koja se u R-u naziva “globalna okolina”). Sve varijable koje smo do sada stvorili možemo vidjeti uz pomoć funkcije ls(). Ukoliko želimo obrisati neke varijable, samo navedemo njihova imena u pozivu funkcije rm() (npr. rm(x, y, z)). Za brisanje svih varijabli iz radne okoline koristimo poziv rm(list=ls()), s time što tu moramo biti oprezni (nema “undo”!).


Zadatak 2.8 - ispis i brisanje varijabli globalne okoline


Konačno, kad god nam treba pomoć oko neke funkcije, imamo sljedeće opcije na raspolaganju:

  • napišemo samo <ime_funkcije> (bez zagrada sa parametrima) i stisnemo - ukoliko je funkcija pisana u R-u (a nije samo proxy prema implementaciji u C-u) na zaslon ćemo dobiti ispis izvornog koda funkcije
  • napišemo help(<ime_funkcije>) ili ?<ime_funkcije> čime dobijamo stranicu pomoći o funkciji sa popisom parametara, primjerima i sl.
  • napišemo example(<ime_funkcije>) pri čemu dobijemo popis primjera korištenja funkcije i dobivenih rezultata

Sljedeći isječak koda prikazuje način korištenja gornjih metoda (zbog štednje prostora ne prikazujemo njihov rezultat).


2.3 Nedostajuće, nepoznate i nemoguće vrijednosti

U R-u postoji tri načina modeliranja “nepostojećih” vrijednosti:

  • NA - (not available) nedostajuća ili nepoznata vrijednost određenog tipa
  • NaN - (not a number) “nemogući” broj, npr. 0/0
  • NULL - nepostojeća vrijednost, doslovno “ništa”

Zadatak 2.9 - rad sa NA, NaN i NULL


Provjeru nedostajućih vrijednosti radimo slično provjeri tipova podataka - koristimo funkcije is.na, is.nan i is.null. Moramo voditi računa da je NaN zapravo podvrsta od NA te da je NULL zapravo potpuno zasebna klasa sa specifičnim ponašanjem - pokušaj aritmetičkih ili logičkih operacija nad NULL vrijednosti neće rezultirati “novom” nepostojećom vrijednosti već upozorenjima i “praznim” rezultatima. Ovo je posebno bitno napomenuti poznavateljima jezika SQL - ono što je NULL u SQL-u je NA u R-u i to je ono što u pravilu koristimo u praksi, dok NULL ima vrlo specifične primjene te ga puno rjeđe koristimo u programskom kodu.


Zadatak 2.10 - provjera vrijednosti NA, NaN i NULL

## [1] TRUE
## [1] TRUE
## logical(0)
## [1] FALSE
## [1] FALSE
## -----------
## [1] FALSE
## [1] TRUE
## logical(0)
## -----------
## [1] FALSE
## [1] FALSE
## [1] TRUE

Za kraj posvetimo se malo NA vrijednosti, budući da ćemo ju vrlo često susretati u praksi. Pojednostavljeno rečeno, ukoliko se pojavljuju NA vrijednosti, možemo očekivati sljedeće nuspojave:

  • rezultati aritmetičkih izraza rezultiraju sa NA vrijednosti
  • rezultati poziva nekih funkcija rezultiraju sa NA (osim ako ne navedemo kompenzacijske akcije, kao npr. parametar na.rm = T koji zapravo znači “ignoriraj NA”)
  • rezultati logičkih izraza mogu ali ne moraju rezultirati sa NA vrijednosti ovisno o tom da li izraz ovisi o NA ili ne (npr. TRUE || NA ima rezultat TRUE, ali FALSE || NA ima rezultat NA)

S ovim zadnjim moramo biti posebno oprezni, budući da NA u uvjetnom izrazu rezultira greškom:

U ovoj lekciji upoznali smo se sa osnovnim elementima jezika R. U radu s R-om u pravilu radimo sa složenim tipovima podataka koje ćemo upoznati u nastavku - a to su vektori, matrice, podatkovni okviri i liste.


Zadaci za vježbu

  1. Što je rezultat sljedećih naredbi? Razmislite o mogućem rezultatu prije izvršavanja.
  1. Kako u R-u izgledaju sljedeći opisni izrazi:
  • “tri puta deset na devetu”
  • “logaritam od 5”
  • “cjelobrojno dijeljenje 10 sa 3”
  • “ostatak cjelobrojnog dijeljenja 10 sa 3”
  • “tangens od 75 stupnjeva” |
  1. Uz pomoć if izraza provjerite da li se rezultat dijeljenja nule s nulom smatra kao vrijednost NA, NaN ili NULL.

  2. Ubacite u varijablu x vrijednost 5. Ispišite sve varijable okoline. Potom u varijablu x ubacite NULL. Postoji li i dalje ova varijabla?


Creative Commons License
Programirajmo u R-u by Damir Pintar is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Based on a work at https://ratnip.github.io/FER_OPJR/