Iterare una sequenza di istruzioni: il ciclo for

L’iterazione è la ripetizione programmata di una porzione di codice, che può andare avanti finché non si presentano delle particolari condizioni. In R, come in tanti altri linguaggi di programmazione, sono previste diverse istruzioni in grado di realizzare un ciclo iterativo; le tre principali sono: for, while e repeat.

Ho sempre pensato che il saper usare i cicli iterativi sia una di quelle competenze che segnano una netta linea di demarcazione fra l’uso di R come semplice strumento di analisi statistica e l’uso di R come linguaggio di programmazione. Si tratta di un aspetto che forse a un informatico potrebbe apparire scontato, ma per me, che informatico non sono, è stato un qualcosa che ha cambiato completamente il mio modo di utilizzare R, aprendomi delle prospettive decisamente nuove. La possibilità di utilizzare i cicli iterativi rende R uno strumento estremamente flessibile e con il quale è possibile fare qualcosa di più che analizzare dati: con R è possibile creare con i dati.

Per chi non nasce come informatico e nel corso nella sua carriera di studente o di professionista non ha mai avuto a che fare con un linguaggio di programmazione, quello con i cicli iterativi può essere uno scontro molto duro (per me lo è stato). In questo post vedremo di studiare il funzionamento del primo dei cicli iterativi: l’istruzione for.

Questa è la forma generale che assume un ciclo for:

for(var in seq) {
    # Codice da ripetere
}

Il ciclo è costituito da due sezioni: l’iniziale dichiarazione della condizione e il corpo di istruzioni da ripetere. Se la condizione è racchiusa tra parentesi tonde, il codice soggetto a iterazione è racchiuso tra parentesi graffe.

Con la dichiarazione “var in seq” stiamo chiedendo a R di costruire una variabile di nome var e di farle assumere sequenzialmente tutti i valori contenuti nel vettore seq. Ipotizzando che seq sia un vettore costituito dagli elementi 3, 3, 4 e 5, var assumerà prima il valore 3, poi nuovamente il valore 3, poi 4 e infine 5. Il numero di iterazioni del ciclo è determinato dalla lunghezza del vettore seq, perché una volta che var ne avrà assunto uno dopo l’altro tutti i valori, il ciclo si concluderà.

Il seguente codice esegue esattamente quanto descritto, stampando a video, iterazione dopo iterazione, il valore assunto dalla variabile i (detta variabile contatore).

for(i in c(3,3,4,5)) {
    print(i)
}

Se il corpo del codice da iterare è costituito da una sola riga, le parentesi graffe possono anche essere omesse.

Facciamo ora qualcosa di più complicato. Dato un vettore x che contiene otto elementi (vedi sotto), vogliamo che a ognuno di essi venga moltiplicato prima il valore 1, poi il valore 2, poi 3, poi 4 e infine 5; a seguito di ogni incremento in x, tutti i valori contenuti nel vettore dovranno essere sommati e il risultato inserito in un altro vettore che conterrà tutti i risultati.

Come primo passaggio, dobbiamo costruire sia il vettore x che un secondo vettore che conterrà tutti i valori che risulteranno dall’espressione sottoposta a iterazione. Dato che dovremo effettuare 5 iterazioni (i dovrà assumere i valori da 1 a 5) i risultati dell’espressione saranno 5, per cui il vettore di risultati dovrà essere in grado di contenere 5 valori.


x <- c(8, 14, 7, 2, 5, 10, 2, 9) res <- rep(NA, 5) [/code]

L’oggetto res – results – contiene cinque NA, che iterazione dopo iterazione il ciclo for dovrà rimpiazzare con i risultati dell’espressione.

Vediamo quindi come realizzare il ciclo:


for(i in 1:5)
res[i] <- sum(x*i) [/code]

Per ogni iterazione, ogni valore in x sarà moltiplicato con l’attuale valore assunto da i; tutti i valori saranno sommati e il risultato verrà salvato nella i-esima posizione del vettore res. Questo è il risultato:

> res
[1]  57 114 171 228 285

Per svolgere questa operazione avremmo anche potuto non utilizzare il ciclo for ma scrivere “manualmente” tutto il codice necessario:


res[1] <- sum(x*1) res[2] <- sum(x*2) res[3] <- sum(x*3) res[4] <- sum(x*4) res[5] <- sum(x*5) [/code]

L’uso dei cicli iterativi richiede però un minor numero di righe di codice, e questo è un indubbio vantaggio. Nel nostro esempio siamo a due righe contro cinque, ma si pensi ai casi in cui si vuole ripetere la stessa operazione su dataset con decine di colonne o centinaia (se non migliaia) di unità statistiche.

Vorrei chiudere con qualche esempio pratico in cui la possibilità di utilizzare un ciclo iterativo ha giocato un ruolo determinante nel salvarmi la vita (sono drammatico, lo so, ma leggendo capirete…).

  • Tempo fa stavo lavorando su un questionario di valutazione psicologica. Il questionario conteneva 51 item, codificati in altrettante colonne di un dataset. Ogni colonna conteneva dei dati mancanti che dovevo rimpiazzare. Il ciclo for mi è costato due righe di codice contro le cinquantuno che altrimenti avrei dovuto scrivere per sostituire quei fastidiosi NA.

  • L’ISTAT organizza i dati del bilancio demografico suddividendoli per provincia; vengono annualmente distribuiti 110 file, tanti quante sono le province. Io avevo la necessità di assemblare tutti i file in un unico dataset. Realizzando un ciclo for in cui i assumeva di volta in volta il nome del file da importare, ho avuto la possibilità di unire 110 dataset in uno unico con pochi passaggi. Provate solo a immaginare cosa sarebbe stato unire manualmente 110 file diversi…

Print Friendly

4 Commenti per “Iterare una sequenza di istruzioni: il ciclo for

  1. Pingback: Realizzare un ciclo iterativo con l’istruzione repeat | InsulaR

  2. doriansorudoriansoru

    Ho scoperto che è possibile utilizzare il ciclo anche per accedere agli elementi di un data.frame per nome.
    Esempio. Ho un data.frame, di nome data, con 20 item (tutti gli item di una scala) chiamati item1, item2, … item20

    Volevo, essendo pignolo, essere certo che R li prendesse come dei numeri interi. Non posso fare as.integer ovunque perché il data.frame contiene anche altro.

    for (i in 1:20) {
    itemName<-paste("item", i, sep="")
    data[itemName]<-as.integer(data[itemName])
    }

    ce piace :)

  3. Pingback: Il ciclo iterativo while | InsulaR

Lascia un Commento