Come sostituire i valori mancanti (NA) in R: na.omit e na.rm
โก Riepilogo intelligente
La sezione "Sostituire i valori mancanti in R" illustra come individuare i valori NA, rimuovere le righe incomplete con `na.omit()` e imputarli con la media o la mediana tramite `mutate()`. Questa guida utilizza il dataset Titanic, in cui sia l'etร che la tariffa presentano valori mancanti.

Cosa sono i valori mancanti in R?
I valori mancanti compaiono quando un'osservazione non ha un valore registrato in una colonna, oppure quando un segnaposto non numerico occupa il posto di un numero. Devono essere rimossi o sostituiti prima di qualsiasi calcolo, perchรฉ la maggior parte delle funzioni di R restituisce NA non appena ne viene rilevato uno.
Questo tutorial mostra come gestire i valori mancanti con la libreria dplyr, parte dell'ecosistema tidyverse per l'analisi dei dati.
Il primo passo รจ sempre quello di scoprire quanti valori mancano e dove.
Come rilevare e contare i valori mancanti in R
Prima di decidere come gestire i valori mancanti, รจ necessario sapere quanti ce ne sono e dove si trovano. R offre quattro controlli, da una semplice risposta sรฌ/no a un conteggio completo per colonna.
# 1. Is there any NA at all? anyNA(df_titanic) # 2. How many in total? sum(is.na(df_titanic)) # 3. How many per column, the most useful view colSums(is.na(df_titanic)) # 4. Percentage missing per column round(colMeans(is.na(df_titanic)) * 100, 1)
In pratica, la funzione da utilizzare รจ `colSums()`. Restituisce un vettore denominato con un conteggio per colonna, che mostra immediatamente se una variabile ha pochi valori mancanti o รจ perlopiรน vuota.
Conteggio delle righe complete. La funzione complete.cases() restituisce TRUE per le righe senza valori mancanti, il che indica in anticipo quanti dati verrebbero scartati dalla funzione na.omit():
sum(complete.cases(df_titanic)) # rows that would survive sum(!complete.cases(df_titanic)) # rows that would be dropped
Un avvertimento riguardo ai segnaposto. R riconosce solo i valori NA. I set di dati spesso codificano i valori mancanti come una stringa vuota, uno spazio, "N/A", "-" o un numero sentinella come -99 o 999. Questi valori superano tutti i controlli sopra descritti senza essere rilevati. Convertili durante l'importazione in modo che il resto del flusso di lavoro funzioni correttamente:
df <- read.csv(PATH, na.strings = c("", " ", "NA", "N/A", "-", "-99"))
Dopo l'importazione, controllate sempre l'intervallo di ogni colonna numerica. Un'etร di -99 o una tariffa di 9999 sono molto piรน pericolose di un onesto valore NA, perchรฉ nessuna funzione vi avviserร in caso di problemi.
Tipi di dati mancanti: MCAR, MAR e MNAR
Il motivo per cui un valore รจ mancante determina se รจ sicuro imputarlo. Gli statistici riconoscono tre meccanismi.
- MCAR, mancante completamente in modo casuale. La probabilitร di essere mancante non รจ correlata a nulla, osservato o meno, ad esempio un sensore che si guasta in momenti casuali. Cadutaping oppure l'imputazione di queste righe non introduce alcuna distorsione, solo una perdita di precisione.
- MAR, mancante in modo casuale. La probabilitร dipende da altre variabili osservate, ma non dal valore mancante in sรฉ. Se fosse meno probabile che l'etร dei passeggeri piรน anziani venisse registrata, l'etร sarebbe MAR (Missing At Random) date le altre colonne. L'imputazione che utilizza tali colonne gestisce bene questo caso.
- MNAR, mancante non a caso. La probabilitร dipende dal valore non osservato stesso, ad esempio i percettori di redditi elevati che si rifiutano di dichiarare il proprio reddito. Nessun metodo di imputazione puรฒ risolvere questo problema basandosi solo sui dati, e la mancanza di dati in sรฉ contiene informazioni che vale la pena registrare in una colonna di flag.
L'imputazione della media, come utilizzata in questo tutorial, รจ giustificabile solo in presenza di MCAR e MAR semplice. Anche in questi casi, presenta un costo noto: riempire ogni lacuna con lo stesso numero riduce la varianza della colonna e ne indebolisce la correlazione con tutto il resto. Per lavori seri, รจ consigliabile utilizzare un metodo basato su modelli, come il pacchetto mice, e mantenere sempre una colonna di flag che indichi quali valori sono stati imputati.
mutare()
mutate() รจ il dplyr Verbo che crea una nuova variabile o sovrascrive una variabile esistente, il che lo rende lo strumento ideale per costruire una copia pulita di una colonna.
Procederemo in due parti. Impareremo come:
- escludere i valori mancanti da un frame di dati
- imputare i valori mancanti alla media e alla mediana
Il verbo mutate() รจ molto facile da usare. Possiamo creare una nuova variabile seguendo questa sintassi:
mutate(df, name_variable_1 = condition, ...) arguments: -df: Data frame used to create a new variable -name_variable_1: Name and the formula to create the new variable -...: No limit constraint. Possibility to create more than one variable inside mutate()
Escludi i valori mancanti (NA)
`na.omit()` รจ una funzione base di R, non un verbo di dplyr, ma funziona comunque correttamente. Elimina tutte le righe che contengono almeno un valore NA. Questa รจ l'opzione piรน veloce, ma raramente la migliore, perchรฉ un singolo valore mancante comporta l'eliminazione dell'intera osservazione.
Per affrontare il problema delle osservazioni mancanti, utilizzeremo il set di dati Titanic. In questo set di dati abbiamo accesso alle informazioni dei passeggeri a bordo durante la tragedia. Questo set di dati ha molte NA di cui occuparsi.
Scarica il file CSV da internet, quindi elenca le colonne che contengono NA:
PATH <- "https://raw.githubusercontent.com/guru99-edu/R-Programming/master/test.csv" df_titanic <- read.csv(PATH, sep = ",") # Return the column names containing missing observations list_na <- colnames(df_titanic)[ apply(df_titanic, 2, anyNA) ] list_na
Produzione:
## [1] "age" "fare"
Qui,
colnames(df_titanic)[apply(df_titanic, 2, anyNA)]
restituisce i nomi delle colonne che contengono almeno un valore mancante.
Nelle colonne etร e tariffa mancano valori.
Possiamo eliminarli con na.omit().
library(dplyr) # Exclude the missing observations df_titanic_drop <-df_titanic %>% na.omit() dim(df_titanic_drop)
Produzione:
## [1] 1045 13
Il nuovo set di dati contiene 1045 righe rispetto alle 1309 del set di dati originale.
Imputare i dati mancanti con la media e la mediana
ร anche possibile imputare, ovvero riempire, i valori mancanti con la media o la mediana. Una buona pratica consiste nel creare due variabili separate per la media e la mediana. Una volta create, possiamo sostituire i valori mancanti con le variabili appena formate.
Utilizzeremo il metodo apply per calcolare la media della colonna con NA. Vediamo un esempio
Passo 1) In precedenza nel tutorial, abbiamo archiviato il nome delle colonne con i valori mancanti nell'elenco chiamato list_na. Utilizzeremo questo elenco
Passo 2) Calcola la media con l'argomento na.rm = TRUE. Questo argomento รจ obbligatorio perchรฉ le colonne contengono dati mancanti e indica a R di ignorarli.
# Create mean average_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na], 2, mean, na.rm = TRUE) average_missing
Code Spiegazione:
Passiamo 4 argomenti nel metodo apply.
- df: df_titanic[,colnames(df_titanic) %in% list_na]. Questo codice restituirร il nome delle colonne dall'oggetto list_na (ad esempio "age" e "fare")
- 2: Calcola la funzione sulle colonne
- media: calcola la media
- na.rm = TRUE: ignora i valori mancanti
Produzione:
## age fare ## 29.88113 33.29548
Abbiamo creato con successo la media delle colonne contenenti le osservazioni mancanti. Questi due valori verranno utilizzati per sostituire le osservazioni mancanti.
Passo 3) Sostituisci i valori NA
Il verbo mutate dalla libreria dplyr รจ utile per creare una nuova variabile. Non vogliamo necessariamente modificare la colonna originale, quindi possiamo creare una nuova variabile senza NA. mutate รจ facile da usare, basta scegliere un nome di variabile e definire come creare questa variabile. Ecco il codice completo
# Create a new variable with the mean and median df_titanic_replace <- df_titanic %>% mutate(replace_mean_age = ifelse(is.na(age), average_missing[1], age), replace_mean_fare = ifelse(is.na(fare), average_missing[2], fare))
Code Spiegazione:
Creiamo due variabili, replace_mean_age e replace_mean_fare come segue:
- replace_mean_age = ifelse(is.na(age), Average_missing[1], age)
- replace_mean_fare = ifelse(is.na(tariffa), Average_missing[2],tariffa)
Se la colonna etร presenta valori mancanti, sostituiscili con il primo elemento di Average_missing (media dell'etร ), altrimenti mantieni i valori originali. Stessa logica per la tariffa
sum(is.na(df_titanic_replace$age))
Produzione:
## [1] 263
Dopo la sostituzione, la nuova colonna non contiene alcun valore mancante:
sum(is.na(df_titanic_replace$replace_mean_age))
Produzione:
## [1] 0
La colonna "etร " originale contiene 263 valori mancanti, mentre la nuova colonna "replace_mean_age" li ha riempiti tutti con l'etร media.
Passo 4) Possiamo anche sostituire le osservazioni mancanti con la mediana.
median_missing <- apply(df_titanic[,colnames(df_titanic) %in% list_na], 2, median, na.rm = TRUE) df_titanic_replace <- df_titanic %>% mutate(replace_median_age = ifelse(is.na(age), median_missing[1], age), replace_median_fare = ifelse(is.na(fare), median_missing[2], fare)) head(df_titanic_replace)
Produzione:
Passo 5) Su un set di dati ampio, il metodo passo passo diventa tedioso. La funzione sapply() riduce l'intera procedura a un'unica istruzione, a costo di non visualizzare mai i valori imputati.
sapply non crea un file Frame dati, quindi possiamo racchiudere la funzione sapply() all'interno di data.frame() per creare un oggetto frame di dati.
# Quick code to replace missing values with the mean df_titanic_impute_mean <- data.frame( sapply( df_titanic, function(x) ifelse(is.na(x), mean(x, na.rm = TRUE), x)))
Imputazione moderna con replace_na() e across()
Gli approcci apply() e sapply() descritti sopra funzionano ancora, ma tidyr e dplyr ora esprimono le stesse operazioni in modo piรน sicuro e leggibile.
replace_na() per valori fissi. tidyr::replace_na() accetta un elenco denominato di colonne e le relative sostituzioni:
library(tidyr) df_titanic %>% replace_na(list(age = 29.88, fare = 33.30))
across() per ogni colonna numerica. Questa รจ la sostituzione diretta e sicura dal punto di vista dei tipi per la riga singola sapply(), e a differenza di sapply() non modifica mai le colonne di tipo carattere o fattore:
library(dplyr) # Mean-impute every numeric column df_titanic %>% mutate(across(where(is.numeric), ~ ifelse(is.na(.x), mean(.x, na.rm = TRUE), .x))) # Median-impute instead df_titanic %>% mutate(across(where(is.numeric), ~ ifelse(is.na(.x), median(.x, na.rm = TRUE), .x)))
โ ๏ธ Perchรฉ la scorciatoia sapply() รจ rischiosa: l'esempio sapply() su una sola riga viene eseguito ogni colonna, comprese quelle di tipo carattere e fattore. Chiamare mean() su queste restituisce NA con un avviso, e sapply() converte quindi l'intero risultato in carattere. La versione across(where(is.numeric), โฆ) sopra evita completamente questo problema.
coalesce() per le colonne di fallback. Quando una seconda colonna puรฒ fornire il valore mancante, coalesce() restituisce la prima voce non mancante tra i suoi argomenti:
df %>% mutate(age_final = coalesce(age, age_estimated, 0))
Tieni traccia di ciรฒ che hai modificato. Aggiungi un flag prima dell'imputazione, in modo che qualsiasi modello successivo possa apprendere dal fatto che un valore era mancante:
df_titanic %>%
mutate(age_was_missing = is.na(age),
age = ifelse(is.na(age), mean(age, na.rm = TRUE), age))
Gestione dei valori mancanti in R: Riferimento al metodo
In questo tutorial vengono illustrati tre approcci:
- Escludere tutte le osservazioni mancanti
- Imputare con la media
- Imputare con la mediana
La tabella seguente riassume le procedure di rilevamento e rimozione:
| Biblioteca | Obiettivo | Code |
|---|---|---|
| base | Elenca le osservazioni mancanti |
colnames(df)[apply(df, 2, anyNA)] |
| base | Rimuovi tutte le righe contenenti NA |
na.omit(df) |
L'imputazione con media o mediana puรฒ essere effettuata in due modi
- Usando applica
- Utilizzando sapply
| Metodo | Dettagli | Vantaggi | Svantaggi |
|---|---|---|---|
| Passo dopo passo con l'applicazione | Controlla le colonne mancanti, calcola la media/mediana, memorizza il valore, sostituisci con mutate() | ร possibile visualizzare la media o la mediana imputata | Piรน tempo di esecuzione. Puรฒ essere lento con set di dati di grandi dimensioni |
| Modo rapido con Sapply | Utilizza sapply() e data.frame() per cercare e sostituire automaticamente i valori mancanti con media/mediana | Codice breve e veloce | I valori imputati non vengono mai mostrati |



