Ersetzen Sie alle 0-Werte durch NA

144

Ich habe einen Datenrahmen mit einigen numerischen Spalten. Einige Zeilen haben einen Wert von 0, der in der statistischen Analyse als Null betrachtet werden sollte. Was ist der schnellste Weg, um den gesamten 0-Wert in R durch NULL zu ersetzen?

Gesehen
quelle
17
Ich glaube nicht, dass Sie durch NULL-Werte ersetzen wollen / können, aber NA dient diesem Zweck in der Umgangssprache.
Chase

Antworten:

243

Ersetzen aller Nullen durch NA:

df[df == 0] <- NA



Erläuterung

1. Es ist nicht das, durch NULLdas Sie Nullen ersetzen möchten. Wie es in heißt ?'NULL',

NULL repräsentiert das Nullobjekt in R.

Das ist einzigartig und kann als das uninformativste und leerste Objekt angesehen werden. 1 Dann wird es nicht so überraschend, dass

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

Das heißt, R reserviert keinen Platz für dieses Nullobjekt. 2 In der Zwischenzeit ?'NA'sehen wir das

NA ist eine logische Konstante der Länge 1, die einen Indikator für fehlende Werte enthält. NA kann zu jedem anderen Vektortyp außer roh gezwungen werden.

Wichtig ist, dass NAes die Länge 1 hat, damit R etwas Platz dafür reserviert. Z.B,

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

Außerdem erfordert die Datenrahmenstruktur, dass alle Spalten die gleiche Anzahl von Elementen aufweisen, damit keine "Löcher" (dh NULLWerte) vorhanden sein können.

Jetzt können Sie Nullen durch NULLin einem Datenrahmen ersetzen, indem Sie alle Zeilen, die mindestens eine Null enthalten, vollständig entfernen. Bei der Verwendung von , zum Beispiel var, covoder cor, ist , dass tatsächlich äquivalent ersten Nullen mit dem Ersetzen NAund Einstellen des Wertes des useals "complete.obs". In der Regel ist dies jedoch unbefriedigend, da dies zu einem zusätzlichen Informationsverlust führt.

2. Anstatt eine Art Schleife auszuführen, verwende ich in der Lösung die df == 0Vektorisierung. df == 0gibt (versuchen Sie es) eine Matrix der gleichen Größe wie dfmit den Einträgen TRUEund zurück FALSE. Außerdem dürfen wir diese Matrix an die Teilmenge übergeben [...](siehe ?'['). Obwohl das Ergebnis von df[df == 0]vollkommen intuitiv ist, mag es seltsam erscheinen, df[df == 0] <- NAden gewünschten Effekt zu erzielen. Der Zuweisungsoperator <-ist in der Tat nicht immer so intelligent und funktioniert auf diese Weise nicht mit einigen anderen Objekten, sondern mit Datenrahmen. siehe ?'<-'.


1 Die leere Menge in der Mengenlehre fühlt sich irgendwie verwandt an.
2 Eine weitere Ähnlichkeit mit der Mengenlehre: Die leere Menge ist eine Teilmenge jeder Menge, aber wir reservieren keinen Platz dafür.

Julius Vainora
quelle
3
Was wäre die äquivalente Syntax für ein data.table-Objekt?
Itpetersen
6
Ich sehe, dass Sie viele Stimmen erhalten haben, aber ich denke nicht, dass dies die Randfälle nicht numerischer Spalten mit Werten von "0" angemessen abdeckt, die nicht auf <NA> gesetzt werden mussten.
IRTFM
33

Angenommen, Ihr data.frame ist eine Mischung aus verschiedenen Datentypen und nicht alle Spalten müssen geändert werden.

Um nur die Spalten 12 bis 18 (von insgesamt 21) zu ändern, tun Sie dies einfach

df[, 12:18][df[, 12:18] == 0] <- NA
userJT
quelle
Dies funktioniert für mich, während die akzeptierte Antwort nicht funktioniert
Patrick Coulombe
23

Ein alternativer Weg ohne die [<-Funktion:

Ein Beispieldatenrahmen dat(schamlos aus der Antwort von @ Chase kopiert):

dat

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

Nullen ersetzt werden kann NAdurch die is.na<-Funktion:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA
Sven Hohenstein
quelle
22

dplyr::na_if() ist eine Option:

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
sbha
quelle
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
Verfolgungsjagd
quelle
12

Da jemand nach der Data.Table-Version gefragt hat und die angegebene data.frame-Lösung nicht mit data.table funktioniert, biete ich die folgende Lösung an.

Verwenden Sie grundsätzlich den :=Operator ->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
Reilstein
quelle
2
Oder for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Sehen Sie hier für eine detailliertere Erörterung von data.table unter Verwendung von Werten zu finden und zu ersetzen.
JWilliman
4

Sie können ersetzen 0mit NAnur in numerischen Feldern (dh Dinge wie Faktoren ausschließlich), aber es funktioniert auf einer Säule- für -Spalte - Basis:

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

Mit einer Funktion können Sie dies auf Ihren gesamten Datenrahmen anwenden:

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))

Obwohl Sie die 1:5durch die Anzahl der Spalten in Ihrem Datenrahmen oder durch ersetzen könnten 1:ncol(df).

Alium Britt
quelle
Ich bin nicht sicher, ob dies die richtige Lösung ist. Was ist mit Spalten 6 und mehr? Sie werden geschnitten.
BenutzerJT
Deshalb schlug ich zu ersetzen 1:5mit 1:ncol(df)am Ende. Ich wollte die Gleichung nicht zu komplex oder schwer lesbar machen.
Alium Britt
Was aber, wenn in den Spalten 6 und 7 der Datentyp char ist und kein Ersatz erfolgen sollte? In meinem Problem muss ich nur in den Spalten 12 bis 15 ersetzt werden, aber der gesamte df hat 21 Spalten (viele dürfen überhaupt nicht berührt werden).
userJT
Für Ihren Datenrahmen können Sie einfach die 1:5zu ändernden Spaltennummern ändern. 12:15Wenn Sie jedoch bestätigen möchten, dass nur numerische Spalten betroffen sind, setzen Sie die zweite Zeile der Funktion in eine if-Anweisung wie folgt : if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt
0

Falls jemand über Google hierher kommt und nach dem Gegenteil sucht (dh wie alle NAs in einem data.frame durch 0 ersetzt werden), lautet die Antwort

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

ODER

Mit dplyr / tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)
stevec
quelle