5 . Kapitulua Kontrol-egiturak eta begiztak
Beste lengoaia guztietan bezala, R n kontrol-egitura eta begizta tipikoak erabil ditzakegu. Jarraian, egitura horien sintaxia eta zenbait adibide jasotzen dira.
5.1 if
agindua
Exekuzio baldintzatua ahalbidetzen duen egiturarik sinpleenak if
eta else if
aginduak dira. Funtzio hauek parametro bakarra dute –balio logiko bat itzultzen duen espresio bat, hain zuzen–. Hona hemen agindu hauen sintaxia.
k <- 5
if (k < 2){
message("k balioa 2 baino txikiagoa da")
}else if (k < 3){
message("k balioa 2 eta 3 balioen artean dago")
}else{
message("k balioa 3 edo handiagoa da")
}
## k balioa 3 edo handiagoa da
5.2 switch
agindua
if
agindua baldintza baten arabera bi kode blokeen artean aukeratzeko erabiltzen da; bi aukera baino gehiago egonez gero, switch
agindua erabil dezakegu. Funtzio horren lehenengo parametroa zenbaki edo string
bat itzultzen duen espresio bat da. Ondoren, definitutako espresioak itzuli dezakeen balio posible bakoitzari dagozkion kode blokeak datoz. Hona hemen sintaxiaren adibide pare bat.
a <- 1
b <- 2
switch(a+b,
"A"={
message("Option A selected")
},
"B"={
message("Option B selected")
},
"C"={
message("Option C selected")
})
## Option C selected
opt <- "B"
switch(opt,
"A"={
message("Option A selected")
},
"B"={
message("Option B selected")
},
"C"={
message("Option C selected")
})
## Option B selected
Lehenengo adibidean espresioak zenbaki bat itzultzen du; kode blokeetatik zenbaki horri dagokiona exekutatzen da –emaitza i bada, i. blokea, alegia–. Bigarren adibidean, berriz, espresioaren emaitza string bat da eta beraz izen bereko blokea exekutatuko da. Azken aukera hau erabiltzeko, noski, kode blokeek izena izan behar dute. Berez, zilegi da izenik ez duen bloke bat uztea. Bloke honek kode lehenetsia definituko du: espresioak itzultzen duen stringa ez badago kode blokeen izenen artean, izenik gabeko kode blokea exekutatuko da.
5.3 for
agindua
Iterazio kopuru ezaguna dituzten begiztak definitzeko for
agindua erabili ohi da. Honetarako, for
funtzioaren barruan, aldagaia in zerrenda
motako espresio bat sortu beharko dugu; iterazio bakoitzean aldagaiak zerrendako balio bat hartuko du. Hona hemen adibide sinple pare bat.
lst <- c("A", "B", "C", "D", "E")
for (l in lst)
message("Uneko elementua:", l, "\n")
## Uneko elementua:A
## Uneko elementua:B
## Uneko elementua:C
## Uneko elementua:D
## Uneko elementua:E
s <- 0
for (i in 1:5) {
s <- s + i
}
s
## [1] 15
5.4 while
agindua
Kode bloke jakin bat baldintza bat bete arte behin eta berriro exekutatu behar denean while
funtzioa erabiliko dugu. Funtzio horrek logical
balio bat itzultzen duen espresio bat du parametro bakartzat. Hona hemen sintaxiaren adibide bat.
i <- 1
while(i < 5) {
message("i aldagaia txikiegia da (", i, ") ...\n")
i <- i + 1
}
## i aldagaia txikiegia da (1) ...
## i aldagaia txikiegia da (2) ...
## i aldagaia txikiegia da (3) ...
## i aldagaia txikiegia da (4) ...
5.5 Bestelako aginduak
Ikusi ditugun aginduez gain, badaude kodearen exekuzioa kontrolatzeko erabil daitezkeen beste hiru funtzio, repeat
, break
eta next
. Informazio gehiago lortzeko, ?Control
exekuta dezakezu.
5.6 Begiztak eta paralelizazioa
R lengoaian dauden funtzio gehienak bektorialak dira eta, beraz, lengoaia eragiketa bektorialak egiteko dago optimizaturik. Hori agerian gelditzen da jarraian dagoen adibidean.
n <- 1000000
x <- 1:n
y <- n:1
system.time({
x + y
})
## user system elapsed
## 0.000 0.004 0.004
system.time({
for (i in 1:n){
x[i] + y[i]
}
})
## user system elapsed
## 0.600 0.000 0.601
Adibide honetan bi bektore sortu ditugu, 1etik n
rako balio osoak hartzen ditu batek eta n
tik 1erakoak besteak. Rn bi bektore hauen osagaiak elementuz elementu batzeko +
eragilea erabil dezakegu zuzenean. Beraz, esan dezakegu, Rn batuketa eragilea bektoriala dela. Are gehiago, eragiketa hau, bektoriala izateaz gain paralelizaturik dago, hau da posizio ezberdinetako batuketak aldi berean egiten dira. Beste hainbat legoaiatan bi bektore elementuz elementu batzeko begizta bat erabili beharko genuke, bigarren kode zatian egiten den bezala. Alabaina, Rn hau ez da estrategiarik egokiena, +
eragilearen paralelizazioa apurtzen baitugu. Hau honela, adibideko bi kodeek berdina egiten dute baina lehenengoa askoz ere azkarragoa da.
Goiko adibide sinpletik ondorio garrantzitsu bat atera behar dugu: Oro har, Rn programatzerako garaian begiztak saihesten saiatu behar gara. Are gehiago, Rn funtzio asko daude definituta eta optimizatuta eta, beraz, ezer inplementatu aurretik, garatu nahi dugun kodea aurrera eramateko behar ditugun funtzioak iada ez direla existitzen egiaztatzea da egokiena.
R ren oinarrizko funtzio gehienak bektorialki funtzionatzeko daude optimizaturik. Zenbait kasutan ordea, guk sortutako funtzioren bat bektorialki aplikatzeko beharra izango dugu; hau burutzeko apply
motako funtzioak erabil ditzakegu. Existitzen diren guztietatik, ondorengo hiruak azalduko ditugu zehaztasun gehiagorekin: sapply
, lapply
eta apply
.
5.6.1 sapply
funtzioa
Zerrenda edo bektore baten elementu guztiei funtzio bat aplikatzeko sapply
funtzioa erabiltzen da; Emaitza, bektore bat edo matrize bat izango da, aukeratutako funtzioak itzultzen duen emaitza motaren arabera. Adibide moduan, character
bektore batek posizio bakoitzean daukan stringaren karaktere kopurua kalkulatuko dugu nchar
funtzioa era bektorialean aplikatuz:
chr.vector <- c("Apply", "a", "Function", "over", "a",
"List", "or", "Vector")
sapply(X=chr.vector, FUN=nchar)
## Apply a Function over a List or Vector
## 5 1 8 4 1 4 2 6
5.6.2 lapply
funtzioa
lapply
funtzioak sapply
ek egiten duen gauza bera egiten du, baina emaitza zerrenda batean gordetzen da matrize batean beharrean. Erabilera berdina da, bakarrik emaitza aldatzen da.
lapply(X=chr.vector, FUN = nchar)
## [[1]]
## [1] 5
##
## [[2]]
## [1] 1
##
## [[3]]
## [1] 8
##
## [[4]]
## [1] 4
##
## [[5]]
## [1] 1
##
## [[6]]
## [1] 4
##
## [[7]]
## [1] 2
##
## [[8]]
## [1] 6
5.6.3 apply
funtzioa
Ikusi ditugun funtzioek bektoreekin eta zerrendekin dihardute, dimentsio bakarreko egiturekin, alegia. Bi dimentsioko egitura bat badugu –matrize edo data.frame
bat–, apply
funtzioa erabil dezakegu funtzioak bektorialki aplikatzeko. Funtzioaren erabilera antzerakoa da, baina oraingo honetan bi dimentsio ditugunez, beste parametro bat behar dugu, funtzioa ea errenkadaka, zutabeka edo elementuka aplikatu behar den adierazteko. Parametro hau MARGIN
da, eta 1 balioa esleitzen badiogu, funtzioa errenkadaka aplikatuko da. Argumentuari 2 balioa esleitzen badiogu, berriz, funtzioa zutabeka aplikatuko da. Azkenik, funtzioa elementuz elementu aplikatu nahi badugu, argumentuari c(1,2)
bektorea esleitu beharko diogu.
m <- matrix(1:200, ncol=20)
apply(m, MARGIN=1, FUN=median)
## [1] 96 97 98 99 100 101 102 103 104 105
apply(m, MARGIN=2, FUN=median)
## [1] 5.5 15.5 25.5 35.5 45.5 55.5 65.5 75.5 85.5 95.5 105.5
## [12] 115.5 125.5 135.5 145.5 155.5 165.5 175.5 185.5 195.5
Goiko adibidean dauden bi deiek matrize baten mediana konputatzen dute, lehenengo kasuan errenkadaka eta bigarren kasuan zutabeka.
5.6.4 Noiz erabili for
eta noiz ez
Oro har, begiztek kodearen eraginkortasunean eragin handia dute, baina eragin hori iterazio kopuruaren araberakoa da; begiztak iterazio gutxi baditu, eragina txikia izango da eta, hortaz, for
egiturak erabil daitezke8. Izan ere, kodearen ulergarritasuna dela eta, kasu horietan begiztak erabiltzea komenigarria da, apply
motako funtzioak baino errazagoak baitira interpretatzeko.
Tamainaz gain, badago beste aspektu bat apply
motako funtzioen eraginkortasuna baldintzatzen duena: sekuentzialtasuna. Kasu batzuetan, kodearen natura sekuentziala izango da, iterazio bakoitzean aurrekoan lortutako emaitza erabili behar dugulako, adibidez. Kasu horietan apply
funtzioak lortzen duen paralelizazioa ez da erabilgarria, hortaz, ez dugu ezer irabazten. Hortaz, horrelako kasuetan for
egiturak erabiltzea egokia da.
5.7 Ariketak
1. Ariketa Idatzi for
begizta bat 1tik 100rako zenbaki bikoiti guztiak idazten dituena. Egin ariketa hau bera begiztarik erabili gabe.
2. Ariketa Idatzi funtzio bat, maximo
izenekoa, begizta bat erabiliz bektore bateko balio maximoa bilatu eta itzultzen duena. Begiztarik erabili gabe, nola egingo zenuke hau?
Sortu matrize honen zutabe guztien batezbestekoak gordetzen dituen bektore bat for
begizta bat erabiliz. Egin ariketa berbera apply
erabiliz. Errepikatu ariketa Rko oinarrizko funtzio bat erabiliz.
4. Ariketa Egin funtzio bat zenbaki bat lehena den konprobatzen duena: lehena bada “x zenbakia lehena da” esaldia pantallaratuko du terminalean eta bestela, “x zenbakia ez da lehena”, kasu bakoitzean, x
dagokion zenbakiarekin ordezkatuz.
5. ariketa Definitu funtzio bat, argumentu bezala zenbaki natural bat n
jasoko duena, eta Fibonacci-ren segidako lehenengo n
zenbakiak gordetzen dituen bektore bat itzultzen duena. Erabili while
agindua. (OHARRA: Fibonnaciren segida ezagutzen ez baduzue, begiratu bere definizioa Wikipedian).
6. ariketa Definitu zerrenda bat, posizio bakoitzean honako bektore bat duena:
- \(x=(1,2,3)\)$
- \(y=(7,5,1,4)\)$
- \(z=(1,2,1,2,1)\)$
- \(t=(a,b,c,d,e)\)$
Erabili for
begizta bat zerrenda horretako elementu bakoitzaren luzera lortzeko. Egin ariketa bera, lapply
komandoa erabiliz.
Are gehiago, kasu batzuetan begiztak eraginkorragoak izan daitezke.↩