[1] 55
Il concetto di iterazione è alla base di qualsiasi operazione nei linguaggi di programmazione. In R molte delle operazioni sono vettorizzate. Questo rende il linguaggio più efficiente e pulito MA nasconde il concetto di iterazione.
Ad esempio la funzione sum()
permette di sommare un vettore di numeri.
Ma cosa si nasconde sotto?
Esempio: se io vi chiedo di usare la funzione print()
per scrivere “hello world” nella console 5 volte, come fate?
Quello che ci manca (e che invece fa la funzione sum()
) è un modo di ripetere una certa operazione, senza effettivamente ripetere il codice manualmente.
Ci sono vari costrutti che ci permettono di ripetere operazioni, i più utilizzati sono:
Ciclo for
Ciclo while
Ciclo repeat
*apply
family
for
Il ciclo for
è una struttura che permette di ripetere un numero finito e pre-determinato di volte una certa porzione di codice.
La scrittura di un ciclo for è:
Se voglio stampare una cosa 5 volte, posso tranquillamente usare un ciclo for:
for
for(){ }
: è l’implementazione in R (in modo simile all’if statement)
i
: questo viene chiamato iteratore o indice. E’ un indice generico che può assumere qualsiasi valore e nome. Per convenzione viene chiamato i, j etc. Questo tiene conto del numero di iterazioni che il nostro ciclo deve fare
in <valori>
: questo indica i valori che assumerà l’iteratore all’interno del ciclo
{ # operazioni }
: sono le operazioni che i ciclo deve eseguire
La potenza del ciclo for sta nel fatto che l’iteratore i assume i valori del vettore specificato dopo in
, uno alla volta:
For
con iteratore vs senzawhile
Il ciclo while
utilizza una condizione logica e non un iteratore e un range di valori come nel for. Il ciclo continuerà fino a che la condizione è TRUE
:
Provate a scrivere questo ciclo while
e vedere cosa succede e capire perchè accade
x = 10
while (x < 15) {
print(x)
}
Il ciclo while
è un ciclo non pre-determinato e quindi necessita sempre di un modo per essere interrotto, facendo diventare la condizione falsa.
repeat
La logica del ciclo repeat
è molto simile a quella del ciclo while
, ma con 3 importanti differenze:
esegue sempre almeno un’interazione
enfatizza la ripetizione fino a che una condizione non viene raggiunta
utilizza il comando break
per terminare
repeat
repeat
vs. while
repeat
valuta la condizione una volta finita l’iterazione, mentre while
all’inizio. Se la condizione non è TRUE
all’inizio, il while non parte mentre repeat si:
sum()
Immaginiamo di non avere la funzione sum()
e di volerla ricreare, come facciamo? Idee?
Scomponiamo concettualmente la somma, sommiamo i numeri da 1 a 10:
prendo il primo e lo sommo al secondo (somma = 1 + 2)
prendo la somma e la sommo al 3 elemento somma = somma + 3 …
In pratica abbiamo:
il nostro vettore da sommare
un oggetto somma che accumula progressivamente le somme precedenti
Mettiamo tutto dentro una funzione (i.e., creo una funzione che replichi quello che fa la funzione somma)
Il ciclo for
è anche utile per simulare dei dati per esempio, supponiamo che in media (tra i nostri 30 partecipanti) ci aspettiamo un’effetto dell’età b_mu uguale a .2
'data.frame': 30 obs. of 4 variables:
$ id : int 1 2 3 4 5 6 7 8 9 10 ...
$ age : int 47 48 33 34 43 49 22 28 37 40 ...
$ age_cat: chr "adulto" "adulto" "adulto" "adulto" ...
$ age_z : num 1.429 1.524 0.107 0.201 1.051 ...
Ora possiamo simulare, attraverso un ciclo for
, la variabile y assumendo che dipenda dall’età (age_z)
set.seed(111) # x replicabilità della simulazione
niter = 1000 # numero di iterazioni
res1 = rep(NA, niter) # vettore di risultati
age_z = mydf$age_z
for(i in 1:niter) {
# effetto
b_mu = rnorm(n_subj, mean = group_mean, sd = var_mean)
# Simulo un vettore y per ogni iterazione,
# che avrà tanti elementi quanti soggetti
y = 0 + b_mu * age_z
# Modello lineare
mod = lm(y ~ 1 + age_z)
res1[i] = mod$coefficients[[2]] # Estraggo l'effetto dell'età
}
Risultato:
Aumentiamo la variabilità:
Risultato:
Lo stesso concetto si può applicare al numero di partecipanti, o alla grandezza dell’effetto atteso. Proprio grazie al for loop è possibile effetuare una power simulation.
Per saperne di più date un’occhiata a questa pagina! :)
for
nestedUna volta compresa la struttura iterativa, si può espandere facilmente inserendo un ciclo dentro un altro:
Supponiamo di avere due gruppi sperimentali (ad esempio, Gruppo di controllo e Gruppo di trattamento), ciascuno con 10 partecipanti. Si vuole misurare una variabile (ad esempio, il tempo di reazione) per ogni partecipante e registrare i risultati in un dataframe:
# Ciclo nested per simulare raccolta dati
set.seed(42) # Per riproducibilità dei dati simulati
for (gruppo in gruppi) {
for (soggetto in 1:num_soggetti) {
# Simulare un tempo di reazione
RT=ifelse(gruppo == "Controllo",
rlnorm(1, mean = log(.500), sd = .050),
# Media diversa per il gruppo Trattamento
rlnorm(1, mean = log(.450), sd = .050))
# Aggiungere i dati al dataframe, aggiungendo una riga
res=rbind(res,
data.frame(Gruppo = gruppo, Soggetto = soggetto, RT = RT))
}
}
'data.frame': 20 obs. of 3 variables:
$ Gruppo : chr "Controllo" "Controllo" "Controllo" "Controllo" ...
$ Soggetto: int 1 2 3 4 5 6 7 8 9 10 ...
$ RT : num 0.535 0.486 0.509 0.516 0.51 ...
Gruppo Soggetto RT
1 Controllo 1 0.5354760
2 Controllo 2 0.4860800
3 Controllo 3 0.5091611
4 Controllo 4 0.5160745
5 Controllo 5 0.5102095
6 Controllo 6 0.4973539
[1] 0.5142776
[1] 0.4476666
Equivalente (e forse più intuitivo)
num_soggetti = 10
gruppo = character()
res2 =data.frame(Gruppo = character(num_soggetti),
Partecipante = integer(num_soggetti), RT = numeric(num_soggetti))
for (i in 1:num_soggetti) {
gruppo[i] = ifelse(i < 5, "Controllo","Trattamento")
RT = ifelse(gruppo[i] == "Controllo",
rlnorm(1, log(.500), .050), rlnorm(1, log(.450), .050))
res2$Gruppo[i] = gruppo[i]
res2$Partecipante[i] = i
res2$RT[i] = RT
}
'data.frame': 10 obs. of 3 variables:
$ Gruppo : chr "Controllo" "Controllo" "Controllo" "Controllo" ...
$ Partecipante: int 1 2 3 4 5 6 7 8 9 10
$ RT : num 0.492 0.457 0.496 0.531 0.495 ...
Gruppo Partecipante RT
1 Controllo 1 0.4923925
2 Controllo 2 0.4573929
3 Controllo 3 0.4957205
4 Controllo 4 0.5313080
5 Trattamento 5 0.4947276
6 Trattamento 6 0.4404179
[1] 0.4942035
[1] 0.4479536
Aprite e tenete aperto questo link:
https://etherpad.wikimedia.org/p/arca-corsoR