00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Funzioni in R

Le funzioni sono blocchi di codice riutilizzabili che svolgono un compito specifico. In R, le funzioni sono oggetti di prima classe: possono essere assegnate a variabili, passate come argomenti e restituite da altre funzioni.

Definire Funzioni con function()

Per creare una funzione in R si utilizza la parola chiave function(), specificando i parametri tra parentesi e il corpo della funzione tra parentesi graffe.

# Definizione di una funzione base
saluta <- function(nome) {
  messaggio <- paste("Ciao,", nome, "! Benvenuto in R.")
  return(messaggio)
}

saluta("Marco")
# [1] "Ciao, Marco ! Benvenuto in R."

Parametri e Argomenti di Default

I parametri possono avere valori predefiniti, rendendo la funzione piu flessibile.

# Funzione con argomenti di default
calcola_area <- function(base, altezza, forma = "rettangolo") {
  if (forma == "rettangolo") {
    area <- base * altezza
  } else if (forma == "triangolo") {
    area <- (base * altezza) / 2
  } else {
    stop("Forma non supportata")
  }
  return(area)
}

calcola_area(5, 3)
# [1] 15
calcola_area(5, 3, forma = "triangolo")
# [1] 7.5

return() vs Ultimo Valore

In R, una funzione restituisce automaticamente l’ultimo valore valutato. L’uso esplicito di return() non e obbligatorio, ma migliora la leggibilita.

# Con return() esplicito
somma_esplicita <- function(a, b) {
  risultato <- a + b
  return(risultato)
}

# Senza return(): restituisce l'ultimo valore
somma_implicita <- function(a, b) {
  a + b
}

somma_esplicita(3, 7)
# [1] 10
somma_implicita(3, 7)
# [1] 10

Quando la funzione contiene logica condizionale, return() esplicito e consigliato per chiarezza:

classifica_voto <- function(voto) {
  if (voto >= 28) return("Ottimo")
  if (voto >= 24) return("Buono")
  if (voto >= 18) return("Sufficiente")
  return("Insufficiente")
}

classifica_voto(30)
# [1] "Ottimo"
classifica_voto(20)
# [1] "Sufficiente"

Funzioni Anonime

Le funzioni anonime non hanno un nome e vengono usate direttamente, spesso come argomento di altre funzioni.

# Funzione anonima usata con sapply
numeri <- 1:5
sapply(numeri, function(x) x^2 + 1)
# [1]  2  5 10 17 26

# Dalla versione R 4.1+, sintassi abbreviata con \()
sapply(numeri, \(x) x^3)
# [1]   1   8  27  64 125

Scope delle Variabili

R utilizza il lexical scoping: una funzione cerca le variabili prima nel proprio ambiente locale, poi in quello genitore.

x <- 10  # Variabile globale

funzione_esempio <- function() {
  y <- 20  # Variabile locale
  cat("x (globale):", x, "\n")
  cat("y (locale):", y, "\n")
}

funzione_esempio()
# x (globale): 10
# y (locale): 20

# y non e accessibile fuori dalla funzione
# print(y)  # Errore: oggetto 'y' non trovato

Per modificare una variabile globale dall’interno di una funzione, si usa l’operatore <<-:

contatore <- 0

incrementa <- function() {
  contatore <<- contatore + 1
}

incrementa()
incrementa()
incrementa()
print(contatore)
# [1] 3

I Tre Punti (…) per Argomenti Variabili

L’argomento speciale ... (dots) permette di passare un numero variabile di argomenti a una funzione.

# Funzione che accetta un numero variabile di argomenti
media_pesata <- function(..., pesi = NULL) {
  valori <- c(...)
  if (is.null(pesi)) {
    return(mean(valori))
  }
  return(sum(valori * pesi) / sum(pesi))
}

media_pesata(10, 20, 30)
# [1] 20
media_pesata(10, 20, 30, pesi = c(1, 2, 3))
# [1] 23.33333
# Passare ... ad altre funzioni
mio_grafico <- function(x, y, ...) {
  plot(x, y, ...)
}

# Gli argomenti extra vengono passati a plot()
# mio_grafico(1:10, (1:10)^2, col = "red", pch = 19, main = "Quadrati")

Funzioni Ricorsive

Una funzione ricorsiva richiama se stessa. E utile per problemi che possono essere suddivisi in sotto-problemi identici.

# Fattoriale ricorsivo
fattoriale <- function(n) {
  if (n <= 1) return(1)
  return(n * fattoriale(n - 1))
}

fattoriale(5)
# [1] 120
fattoriale(10)
# [1] 3628800
# Fibonacci ricorsivo
fibonacci <- function(n) {
  if (n <= 1) return(n)
  return(fibonacci(n - 1) + fibonacci(n - 2))
}

sapply(0:10, fibonacci)
# [1]  0  1  1  2  3  5  8 13 21 34 55

La Famiglia Apply

Le funzioni della famiglia apply permettono di applicare una funzione a elementi di strutture dati senza usare cicli espliciti, rendendo il codice piu conciso e spesso piu efficiente.

sapply() - Semplifica il risultato

sapply() applica una funzione a ogni elemento di un vettore o lista e restituisce un vettore o matrice.

# Applicare una funzione a ogni elemento
numeri <- list(1:5, 6:10, 11:15)
sapply(numeri, mean)
# [1]  3  8 13

sapply(numeri, sum)
# [1] 15 40 65

lapply() - Restituisce una lista

lapply() funziona come sapply() ma restituisce sempre una lista.

parole <- c("ciao", "mondo", "r")
lapply(parole, toupper)
# [[1]]
# [1] "CIAO"
# [[2]]
# [1] "MONDO"
# [[3]]
# [1] "R"

tapply() - Applica per gruppi

tapply() applica una funzione a sottogruppi di un vettore definiti da un fattore.

# Vendite per regione
vendite <- c(100, 200, 150, 300, 250, 180)
regione <- c("Nord", "Sud", "Nord", "Sud", "Nord", "Sud")

tapply(vendite, regione, mean)
#     Nord      Sud
# 166.6667 226.6667

tapply(vendite, regione, sum)
# Nord  Sud
#  500  680

mapply() - Versione multivariata

mapply() applica una funzione a piu vettori in parallelo, elemento per elemento.

# Applicare una funzione a piu vettori
basi <- c(3, 5, 7)
altezze <- c(4, 6, 8)

mapply(function(b, h) b * h / 2, basi, altezze)
# [1]  6 15 28

Conclusione

Le funzioni sono il cuore della programmazione in R. Permettono di organizzare il codice in blocchi riutilizzabili, migliorando leggibilita e manutenibilita. Padroneggiare i concetti di scope, argomenti variabili e la famiglia apply consente di scrivere codice R idiomatico ed efficiente, evitando cicli espliciti e sfruttando appieno la natura vettoriale del linguaggio.