Sostituisci tutti i 0 valori in NA


144

Ho un dataframe con alcune colonne numeriche. Alcune righe hanno un valore 0 che deve essere considerato nullo nell'analisi statistica. Qual è il modo più veloce per sostituire tutto il valore 0 in NULL in R?


17
Non penso che tu voglia / possa sostituire con valori NULL, ma NA serve a questo scopo in R lingo.
Chase,

Risposte:


243

Sostituzione di tutti gli zeri in NA:

df[df == 0] <- NA



Spiegazione

1. Non è NULLquello con cui dovresti sostituire gli zeri. Come dice in ?'NULL',

NULL rappresenta l'oggetto null in R

che è unico e, immagino, può essere visto come l'oggetto più disinformativo e vuoto. 1 Quindi non è così sorprendente

data.frame(x = c(1, NULL, 2))
#   x
# 1 1
# 2 2

Cioè, R non riserva spazio per questo oggetto null. 2 Nel frattempo, guardando ?'NA'lo vediamo

NA è una costante logica di lunghezza 1 che contiene un indicatore di valore mancante. NA può essere forzato su qualsiasi altro tipo di vettore ad eccezione di raw.

È importante sottolineare che NAè di lunghezza 1 in modo che R riservi un po 'di spazio per esso. Per esempio,

data.frame(x = c(1, NA, 2))
#    x
# 1  1
# 2 NA
# 3  2

Inoltre, la struttura del frame di dati richiede che tutte le colonne abbiano lo stesso numero di elementi in modo che non possano esserci "buchi" (ovvero NULLvalori).

Ora è possibile sostituire gli zero NULLin un frame di dati, nel senso di rimuovere completamente tutte le righe contenenti almeno uno zero. Quando si utilizza, ad esempio, var, cov, o cor, che in realtà è equivalente alla sostituzione prima zeri con NAe impostando il valore di usecome "complete.obs". In genere, tuttavia, ciò non è soddisfacente in quanto comporta una perdita di informazioni aggiuntiva.

2. Invece di eseguire una sorta di ciclo, nella soluzione utilizzo la df == 0vettorializzazione. df == 0restituisce (provalo) una matrice delle stesse dimensioni di df, con le voci TRUEe FALSE. Inoltre, ci è anche permesso di passare questa matrice al sottoinsieme [...](vedi ?'['). Infine, mentre il risultato di df[df == 0]è perfettamente intuitivo, può sembrare strano che df[df == 0] <- NAdia l'effetto desiderato. In <-effetti, l' operatore di assegnazione non è sempre così intelligente e non funziona in questo modo con alcuni altri oggetti, ma lo fa con i frame di dati; vedi ?'<-'.


1 L'insieme vuoto nella teoria dell'insieme sembra in qualche modo correlato.
2 Un'altra somiglianza con la teoria degli insiemi: l'insieme vuoto è un sottoinsieme di ogni insieme, ma non ci riserviamo spazio.


3
Quale sarebbe la sintassi equivalente per un oggetto data.table?
itpetersen

6
Vedo che hai ottenuto molti voti, ma non penso che questo copra in modo appropriato i casi limite di colonne non numeriche con valori di "0" che non sono stati richiesti per essere impostati su <NA>.
IRTFM,

33

Suppongo che data.frame sia un mix di tipi di dati diversi e non tutte le colonne debbano essere modificate.

per modificare solo le colonne da 12 a 18 (del totale 21), basta fare questo

df[, 12:18][df[, 12:18] == 0] <- NA

Questo funziona per me, mentre la risposta accettata no
Patrick Coulombe il

23

Un modo alternativo senza la [<-funzione:

Un frame di dati di esempio dat(copiato spudoratamente dalla risposta di @ Chase):

dat

  x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0

Gli zeri possono essere sostituiti con NAla is.na<-funzione:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA

22

dplyr::na_if() è un'opzione:

library(dplyr)  

df <- data_frame(col1 = c(1, 2, 3, 0),
                 col2 = c(0, 2, 3, 4),
                 col3 = c(1, 0, 3, 0),
                 col4 = c('a', 'b', 'c', 'd'))

na_if(df, 0)
# A tibble: 4 x 4
   col1  col2  col3 col4 
  <dbl> <dbl> <dbl> <chr>
1     1    NA     1 a    
2     2     2    NA b    
3     3     3     3 c    
4    NA     4    NA d

14
#Sample data
set.seed(1)
dat <- data.frame(x = sample(0:2, 5, TRUE), y = sample(0:2, 5, TRUE))
#-----
  x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0

#replace zeros with NA
dat[dat==0] <- NA
#-----
   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA

12

Poiché qualcuno ha richiesto la versione Data.Table di ciò e poiché la soluzione data.frame fornita non funziona con data.table, sto fornendo la soluzione di seguito.

Fondamentalmente, utilizzare l' :=operatore ->DT[x == 0, x := NA]

library("data.table")

status = as.data.table(occupationalStatus)

head(status, 10)
    origin destination  N
 1:      1           1 50
 2:      2           1 16
 3:      3           1 12
 4:      4           1 11
 5:      5           1  2
 6:      6           1 12
 7:      7           1  0
 8:      8           1  0
 9:      1           2 19
10:      2           2 40


status[N == 0, N := NA]

head(status, 10)
    origin destination  N
 1:      1           1 50
 2:      2           1 16
 3:      3           1 12
 4:      4           1 11
 5:      5           1  2
 6:      6           1 12
 7:      7           1 NA
 8:      8           1 NA
 9:      1           2 19
10:      2           2 40

2
Or for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Vedi qui per una discussione più dettagliata sull'uso di data.table per trovare e sostituire i valori.
JWilliman,

4

Puoi sostituirlo 0con NAsolo nei campi numerici (cioè escludendo cose come i fattori), ma funziona su una colonna per colonna:

col[col == 0 & is.numeric(col)] <- NA

Con una funzione, puoi applicarlo a tutto il tuo frame di dati:

changetoNA <- function(colnum,df) {
    col <- df[,colnum]
    if (is.numeric(col)) {  #edit: verifying column is numeric
        col[col == -1 & is.numeric(col)] <- NA
    }
    return(col)
}
df <- data.frame(sapply(1:5, changetoNA, df))

Sebbene sia possibile sostituire il 1:5con il numero di colonne nel frame di dati o con 1:ncol(df).


Non sono sicuro che questa sia la soluzione corretta. Che dire delle colonne 6 e di più. Saranno tagliati.
userJT

Ecco perché ho suggerito di sostituirlo 1:5con 1:ncol(df)alla fine. Non volevo rendere l'equazione troppo complessa o difficile da leggere.
Alium Britt,

ma cosa succede se nelle colonne 6 e 7 - il tipo di dati è char e non si dovrebbe fare alcuna sostituzione. Nel mio problema, ho bisogno di essere sostituito solo nelle colonne da 12 a 15 ma l'intero df ha 21 colonne (molte non devono essere toccate affatto).
userJT

Per la cornice di dati si può solo cambiare l' 1:5ai numeri colonna che si desidera modificati, come 12:15, ma se si voleva confermare che interesserà solo le colonne numeriche poi basta avvolgere la seconda linea della funzione in un'istruzione if, come questo: if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt,

0

Nel caso in cui qualcuno arrivi qui tramite Google alla ricerca del contrario (ovvero come sostituire tutte le NA in un data.frame con 0), la risposta è

df[is.na(df)] <- 0

O

Usando dplyr / tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.