Tipi di Dati in R
In R, i tipi di dati (chiamati anche tipi atomici) sono gli elementi fondamentali su cui si costruisce ogni analisi. R e’ un linguaggio tipizzato dinamicamente, il che significa che non e’ necessario dichiarare esplicitamente il tipo di una variabile. Il tipo viene inferito automaticamente dal valore assegnato. Vediamo nel dettaglio ciascun tipo di dato disponibile.
Numeric (Numeri Reali)
Il tipo numeric e’ il tipo numerico predefinito in R. Rappresenta numeri reali a virgola mobile (double precision). Qualsiasi numero scritto senza il suffisso L viene interpretato come numeric.
x <- 42
y <- 3.14
z <- -0.001
class(x) # [1] "numeric"
class(y) # [1] "numeric"
class(z) # [1] "numeric"
# Anche i numeri interi senza L sono numeric
typeof(x) # [1] "double"
# Operazioni con numeric
risultato <- x + y
print(risultato) # [1] 45.14
R supporta anche valori speciali per i numeri:
# Infinito
inf_positivo <- Inf
inf_negativo <- -Inf
# Not a Number
nan_valore <- 0 / 0
cat("Infinito:", inf_positivo, "\n") # Inf
cat("NaN:", nan_valore, "\n") # NaN
cat("1 / 0 =", 1 / 0, "\n") # Inf
cat("Is infinite:", is.infinite(Inf), "\n") # TRUE
cat("Is NaN:", is.nan(nan_valore), "\n") # TRUE
Integer (Numeri Interi)
Per creare esplicitamente un valore intero in R, bisogna aggiungere il suffisso L al numero. Senza questo suffisso, il numero viene trattato come numeric (double).
a <- 42L
b <- -10L
c <- 0L
class(a) # [1] "integer"
typeof(a) # [1] "integer"
# Confronto tra integer e numeric
x_numeric <- 42
x_integer <- 42L
cat("42 e' integer?", is.integer(x_numeric), "\n") # FALSE
cat("42L e' integer?", is.integer(x_integer), "\n") # TRUE
# Gli integer occupano meno memoria
cat("Dimensione numeric:", object.size(rep(1.0, 1000)), "bytes\n")
cat("Dimensione integer:", object.size(rep(1L, 1000)), "bytes\n")
Il suffisso L e’ particolarmente utile quando si lavora con indici o contatori, dove i valori interi sono piu’ appropriati.
# Sequenza di interi
sequenza <- 1L:10L
class(sequenza) # [1] "integer"
print(sequenza) # [1] 1 2 3 4 5 6 7 8 9 10
Character (Stringhe di Testo)
Il tipo character rappresenta stringhe di testo. Le stringhe possono essere racchiuse tra virgolette doppie " o singole '.
nome <- "Mario Rossi"
saluto <- 'Ciao a tutti'
vuota <- ""
class(nome) # [1] "character"
class(vuota) # [1] "character"
# Lunghezza della stringa
nchar(nome) # [1] 11
# Concatenazione di stringhe
frase <- paste("Ciao,", nome, "!")
print(frase) # [1] "Ciao, Mario Rossi !"
# paste0 senza spazi separatori
frase2 <- paste0("Benvenuto, ", nome, "!")
print(frase2) # [1] "Benvenuto, Mario Rossi!"
# Sottostringa
cognome <- substr(nome, 7, 11)
print(cognome) # [1] "Rossi"
# Conversione in maiuscolo e minuscolo
toupper(nome) # [1] "MARIO ROSSI"
tolower(nome) # [1] "mario rossi"
Logical (Valori Booleani)
Il tipo logical rappresenta valori booleani: TRUE o FALSE. Sono fondamentali per le espressioni condizionali e il filtraggio dei dati.
vero <- TRUE
falso <- FALSE
class(vero) # [1] "logical"
# Le abbreviazioni T e F funzionano ma sono sconsigliate
t_abbrev <- T # Equivalente a TRUE
f_abbrev <- F # Equivalente a FALSE
# Operazioni logiche
cat("TRUE & FALSE:", TRUE & FALSE, "\n") # FALSE
cat("TRUE | FALSE:", TRUE | FALSE, "\n") # TRUE
cat("!TRUE:", !TRUE, "\n") # FALSE
# I logical si comportano come numeri (TRUE=1, FALSE=0)
cat("TRUE + TRUE:", TRUE + TRUE, "\n") # 2
cat("sum(c(T,T,F,T)):", sum(c(TRUE, TRUE, FALSE, TRUE)), "\n") # 3
# Risultato di confronti
x <- 10
cat("x > 5:", x > 5, "\n") # TRUE
cat("x == 20:", x == 20, "\n") # FALSE
Complex (Numeri Complessi)
Il tipo complex rappresenta numeri complessi con parte reale e parte immaginaria. La parte immaginaria viene indicata con il suffisso i.
z1 <- 3 + 4i
z2 <- complex(real = 2, imaginary = -1)
class(z1) # [1] "complex"
# Operazioni con numeri complessi
somma <- z1 + z2
print(somma) # [1] 5+3i
prodotto <- z1 * z2
print(prodotto) # [1] 10+5i
# Parte reale e immaginaria
cat("Parte reale:", Re(z1), "\n") # 3
cat("Parte immaginaria:", Im(z1), "\n") # 4
cat("Modulo:", Mod(z1), "\n") # 5
cat("Argomento:", Arg(z1), "\n") # 0.9272952
# Coniugato
cat("Coniugato:", Conj(z1), "\n") # 3-4i
Raw (Byte Grezzi)
Il tipo raw rappresenta byte grezzi. Viene utilizzato raramente nella programmazione quotidiana, ma e’ utile quando si lavora con dati binari o connessioni di rete.
# Creazione di valori raw
r1 <- as.raw(0x1a)
r2 <- charToRaw("Ciao")
class(r1) # [1] "raw"
print(r1) # [1] 1a
print(r2) # [1] 43 69 61 6f
# Riconversione a carattere
rawToChar(r2) # [1] "Ciao"
# Operazioni bit a bit
a <- as.raw(0xff)
b <- as.raw(0x0f)
cat("AND:", as.raw(bitwAnd(as.integer(a), as.integer(b))), "\n")
cat("OR:", as.raw(bitwOr(as.integer(a), as.integer(b))), "\n")
Funzioni di Verifica del Tipo
R offre una famiglia di funzioni is.*() per verificare il tipo di un valore e as.*() per convertire tra tipi.
Funzioni is.*()
x <- 42
y <- "testo"
z <- TRUE
w <- 3 + 2i
cat("is.numeric(42):", is.numeric(x), "\n") # TRUE
cat("is.character('testo'):", is.character(y), "\n") # TRUE
cat("is.logical(TRUE):", is.logical(z), "\n") # TRUE
cat("is.complex(3+2i):", is.complex(w), "\n") # TRUE
cat("is.integer(42):", is.integer(x), "\n") # FALSE (e' double)
cat("is.integer(42L):", is.integer(42L), "\n") # TRUE
# Verifiche speciali
cat("is.na(NA):", is.na(NA), "\n") # TRUE
cat("is.null(NULL):", is.null(NULL), "\n") # TRUE
Funzioni as.*() (Conversione tra Tipi)
Le funzioni as.*() consentono di convertire un valore da un tipo a un altro. Questo processo e’ chiamato coercion.
# Da numeric a integer
n <- 3.7
i <- as.integer(n)
cat("as.integer(3.7):", i, "\n") # 3 (troncamento, non arrotondamento)
# Da numeric a character
s <- as.character(42)
cat("as.character(42):", s, "\n") # "42"
class(s) # [1] "character"
# Da character a numeric
num <- as.numeric("3.14")
cat("as.numeric('3.14'):", num, "\n") # 3.14
# Da logical a numeric
cat("as.numeric(TRUE):", as.numeric(TRUE), "\n") # 1
cat("as.numeric(FALSE):", as.numeric(FALSE), "\n") # 0
# Da numeric a logical
cat("as.logical(0):", as.logical(0), "\n") # FALSE
cat("as.logical(1):", as.logical(1), "\n") # TRUE
cat("as.logical(42):", as.logical(42), "\n") # TRUE
# Conversione impossibile genera NA con warning
risultato <- as.numeric("abc")
cat("as.numeric('abc'):", risultato, "\n") # NA (con warning)
Gerarchia di Coercion
Quando R combina valori di tipi diversi in un vettore, applica una conversione automatica seguendo questa gerarchia: logical < integer < numeric < complex < character.
# Coercion automatica nei vettori
v1 <- c(TRUE, 42L)
cat("logical + integer:", class(v1), "\n") # integer
print(v1) # [1] 1 42
v2 <- c(42L, 3.14)
cat("integer + numeric:", class(v2), "\n") # numeric
print(v2) # [1] 42.00 3.14
v3 <- c(3.14, "testo")
cat("numeric + character:", class(v3), "\n") # character
print(v3) # [1] "3.14" "testo"
v4 <- c(TRUE, 3.14, "ciao")
cat("mixed:", class(v4), "\n") # character
print(v4) # [1] "TRUE" "3.14" "ciao"
Conclusioni
Comprendere i tipi di dati in R e’ fondamentale per lavorare efficacemente con il linguaggio. R offre sei tipi atomici principali: numeric, integer, character, logical, complex e raw. Le funzioni class(), typeof(), is.*() e as.*() sono strumenti essenziali per verificare e convertire i tipi di dati. La coercion automatica segue una gerarchia precisa che e’ importante conoscere per evitare comportamenti inattesi durante la manipolazione dei dati.