Il debugging e la gestione degli errori nel linguaggio R

In questa lezione esploriamo il debugging e la gestione degli errori nel linguaggio R.

Cos'è il debugging? Un linguaggio di programmazione è come un laboratorio per l'esperimentazione dei dati. Immagina che stai lavorando in un laboratorio: hai bisogno di strumenti per misurare, analizzare, e a volte qualcosa va storto. Nel mondo della programmazione, questi "strumenti" sono le tecniche di debugging.

Prima di tutto, quando incontri un errore, leggi attentamente il messaggio.

Il linguaggio R ti sta dicendo cosa non va. È come un esperimento che non va come previsto: non ignorarlo, ascoltalo.

Ad esempio, se vedi un errore come il seguente, significa che stai cercando di utilizzare un oggetto `y` che non esiste nel tuo ambiente di lavoro.

Error in funzione(x) : oggetto 'y' non trovato

Fortunatamente R ha diversi strumenti di debugging che ti permettono di gestire situazioni in cui qualcosa può andare storto nel tuo codice.

Vediamo qualche tecnica utile per fare il debugging in R.

Visualizzare lo stato delle variabile durante l'esecuzione

Una tecnica semplice ma efficace per indagare è usare l'istruzione print() per visualizzare i valori delle variabili in diversi punti del tuo script durante l'esecizione. 

È come aggiungere piccoli indicatori nel tuo esperimento per vedere dove le cose vanno storte.

Se una parte del tuo codice non funziona, potresti aggiungere print(nome_variabile) per vedere quale valore ha quella variabile in quel momento.

Ad esempio, in questo codice c'è un errore.

  1. calcola_media <- function(numeri) {
  2.   somma <- sum(numeri)
  3.   lunghezza <- length(numeri)
  4.   media <- somma / lunghezza
  5.   return(media)
  6. }
  7. # Nota: "4" è una stringa, non un numero.
  8. numeri <- c(1, 2, 3, "4", 5) 
  9. media_calcolata <- calcola_media(numeri)
  10. print("Media finale:")
  11. print(media_calcolata)

Quando lo esegui, lo script va in errore perché uno degli elementi dell'array numeri è una stringa anziché un numero, impedendo il calcolo della media.

Errore in sum(numeri) : argomento con 'type' (character) non valido

Se non riesci a capire subito la causa del problema leggendo l'errore, potresti inserire delle istruzioni print() per fare una diagnosi durante l'esecuzione dello script.

  1. calcola_media <- function(numeri) {
  2.   print("Valori in input:")
  3.   print(numeri)
  4.   somma <- sum(numeri)
  5.   print("Somma calcolata:")
  6.   print(somma)
  7.   lunghezza <- length(numeri)
  8.   media <- somma / lunghezza
  9.   return(media)
  10. }
  11. numeri <- c(1, 2, 3, "4", 5)
  12. media_calcolata <- calcola_media(numeri)
  13. print("Media finale:")
  14. print(media_calcolata)

In questo modo, quando esegui questo script modificato, vedrai lo stato delle variabili in diversi punti del codice.

Questo ti aiuterà a capire cosa sta accadendo dentro la funzione calcola_media.

[1] "Valori in input:"
[1] 1 2 3 "4" 5
Errore in sum(numeri) : argomento con 'type' (character) non valido

Noterai che l'array "numeri" contiene al suo interno una stringa, che causa il problema nel calcolo della media.

La sospensione dell'esecuzione dello script

Un'altra tecnica di debugging utile per un'analisi più approfondita si basa sulla funzione browser().

Si tratta di un potente strumento del linguaggio R che mette il tuo script in pausa durante l'esecuzione e ti permette di esplorare l'ambiente operativo.

In pratica sospende l'esecuzione ma non la interrompe del tutto, perché ti permette di andare avanti passo dopo passo e di vedere come cambiano i valori delle variabili. È come fermare il tempo nel tuo laboratorio per esaminare tutto con calma.

Ad esempio, inserisci browser() nel punto del tuo script dove pensi ci sia il problema. Il codice si fermerà lì e potrai eseguire comandi R per ispezionare le variabili.

  1. calcola_somma <- function(a, b) {
  2.    # Inseriamo browser() qui
  3.    browser()
  4.    risultato <- a + b
  5.    return(risultato)
  6. }
  7. a <- 5
  8. b <- "3"
  9. somma <- calcola_somma(a, b)
  10. print(somma)

Quando esegui questo script, l'esecuzione si fermerà dove hai inserito browser().

Sul terminale compare un prompt speciale con la scritta "Browse".

Browse[1]>

A questo punto, sei in una sessione di debug interattiva dove puoi:

  • Digitare n e premere invio per passare alla riga successiva del codice.
  • Digitare il nome di una variabile per vedere il suo valore corrente.
  • Eseguire altri comandi R per testare le tue ipotesi sul problema.

Ad esempio, potresti digitare a e b per vedere i loro valori.

Noteresti che b è una stringa "3", il che spiega perché la somma non funziona come previsto.

Browse[1]> a
[1] 5
Browse[1]> b
[1] "3"

Dopo aver finito la tua indagine, puoi digitare c per continuare l'esecuzione normale dello script.

In breve, l'istruzione browser() è uno strumento molto utile perché ti permette di "entrare" nel tuo codice e guardarti intorno, proprio come un fisico sperimentale che si avvicina più da vicino ai suoi strumenti per capire meglio un fenomeno.

La gestione degli errori

A volte, vuoi che il tuo script continui a funzionare anche se incontra un errore.

In questo caso, puoi usare la struttura try() o tryCatch().

Queste strutture ti permetto di eseguire un blocco di codice e di intercettare e correggere gli eventuali errori tramite il programma stesso, senza causare un'interruzione dell'esecuzione.

In altre parole, queste strutture eseguono il codice o la funzione , e se ci sarà un errore, lo gestiranno senza interrompere l'esecuzione dell'intero script.

Ad esempio, immagina di avere una funzione che può generare un errore.

Per esempio, una funzione che divide due numeri, ma a volte il divisore potrebbe essere una stringa, il che causerebbe un errore.

  1. dividi <- function(a, b) {
  2. return(a / b)
  3. }
  4. # Eseguire la funzione con try
  5. risultato <- try(dividi(10, "2"))
  6. if (inherits(risultato, "try-error")) {
  7.     print("Si è verificato un errore durante la divisione")
  8. } else {
  9.     print(risultato)
  10. }
  11. print("fine del programma")

In questo esempio, try(dividi(10, 0)) tenta di eseguire la divisione.

Se si verifica un errore (divisione per una stringa), invece di interrompere l'intero script, l'istruzione try cattura l'errore.

Usando l'istruzione inherits, puoi controllare se "risultato" è un errore e gestirlo di conseguenza.

Error in a/b : argomento non numerico passato ad un operatore binario
[1] "Si è verificato un errore durante la divisione"
[1] "fine programma"

Come puoi notare, dopo aver intercettato l'errore il programma ha continuato l'esecuzione stampando "fine del programma").

Esempio con tryCatch()

Il comando tryCatch() è più sofisticato e ti permette di gestire diversi tipi di errori in modi diversi.

  1. risultato <- tryCatch({
  2. dividi(10, 0)
  3. }, warning = function(w) {
  4. print("Si è verificato un avviso")
  5. }, error = function(e) {
  6. print("Si è verificato un errore")
  7. NA # Restituisci NA in caso di errore
  8. }, finally = {
  9. print("Operazione di divisione tentata")
  10. })
  11. print(risultato)

In questo esempio, tryCatch() tenta di eseguire la divisione all'interno del suo primo argomento.

Se si verifica un errore, la funzione specificata nell'argomento `error` viene eseguita, stampa un messaggio e restituisce `NA`.

Nota che l'argomento finally è eseguito sempre, indipendentemente dal fatto che si verifichi un errore o meno.

[1] "Si è verificato un errore"
[1] "Operazione di divisione tentata"
[1] NA

In conclusione, il debugging in R, come in ogni forma di esplorazione scientifica, richiede pazienza, curiosità e un approccio metodico.

Ricorda, ogni errore è un'opportunità per imparare qualcosa di nuovo.

Sperimenta con questi strumenti e tecniche, e vedrai che con il tempo diventerai più abile nel trovare e risolvere i problemi nel tuo codice.




Se qualcosa non ti è chiaro, scrivi la tua domanda nei commenti.




FacebookTwitterLinkedinLinkedin