So ersetzen Sie NA-Werte in einer Tabelle für ausgewählte Spalten

81

Es gibt viele Beiträge zum Ersetzen von NA-Werten. Mir ist bewusst, dass man NAs in der folgenden Tabelle / im folgenden Frame durch die folgenden ersetzen könnte:

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

Aber was ist, wenn ich es nur auf bestimmte Spalten beschränken möchte? Lassen Sie mich Ihnen ein Beispiel zeigen.

Beginnen wir zunächst mit einem Datensatz.

set.seed(1234)
x <- data.frame(a=sample(c(1,2,NA), 10, replace=T),
                b=sample(c(1,2,NA), 10, replace=T), 
                c=sample(c(1:5,NA), 10, replace=T))

Welches gibt:

    a  b  c
1   1 NA  2
2   2  2  2
3   2  1  1
4   2 NA  1
5  NA  1  2
6   2 NA  5
7   1  1  4
8   1  1 NA
9   2  1  5
10  2  1  1

Ok, also möchte ich die Ersetzung nur auf die Spalten 'a' und 'b' beschränken. Mein Versuch war:

x[is.na(x), 1:2]<-0

und:

x[is.na(x[1:2])]<-0

Welches funktioniert nicht.

Mein data.table-Versuch, bei dem y<-data.table(x)es offensichtlich nie funktionieren würde:

y[is.na(y[,list(a,b)]), ]

Ich möchte Spalten innerhalb des is.na-Arguments übergeben, aber das würde offensichtlich nicht funktionieren.

Ich möchte dies in einem data.frame und einer data.table tun. Mein Endziel ist es, das 1: 2 bis 0: 1 in 'a' und 'b' neu zu codieren, während 'c' so bleibt, wie es ist, da es keine logische Variable ist. Ich habe eine Reihe von Spalten, deshalb möchte ich es nicht einzeln tun. Und ich möchte nur wissen, wie das geht.

Hast du irgendwelche Vorschläge?

jnam27
quelle

Antworten:

114

Du kannst tun:

x[, 1:2][is.na(x[, 1:2])] <- 0

oder besser (IMHO), verwenden Sie die Variablennamen:

x[c("a", "b")][is.na(x[c("a", "b")])] <- 0

In beiden Fällen 1:2oder c("a", "b")kann durch einen vordefinierten Vektor ersetzt werden.

flodel
quelle
Das macht den Job. Was ist, wenn ich nach '1' suchen möchte? Ich habe versucht, es zu ändern, aber ich konnte es nicht zum Laufen bringen.
jnam27
5
Wahrscheinlich so:x[, 1:2][x[, 1:2] == 1] <- 0
Flodel
@flodel Warum xakzeptiert die Datentabelle eine Matrix nur bei der Zuweisung als erstes Mitglied? Ist diese Funktion irgendwo dokumentiert? Ich denke auch, dass Sie vergessen haben, in Ihrem zweiten Beispiel ein Komma vor die Vektoren mit den Spaltennamen zu setzen.
ChiseledAbs
@ChiseledAbs, ich denke, Sie beziehen sich auf die Matrixindizierung (siehe zum Beispiel stackoverflow.com/a/13999583/1201032 ), aber es ist nicht auf Zuweisungen beschränkt, sondern kann auch zum Extrahieren von Daten verwendet werden. Zum fehlenden Komma: nein. Data.frames sind Listen von Spalten. Wenn Sie also ein einzelnes Argument verwenden [, werden die angegebenen Spalten extrahiert (siehe stackoverflow.com/a/21137524/1201032 ). Ich hoffe, dies beantwortet Ihre Frage, aber bitte vermeiden Sie es in Zukunft, sehr alte Antworten wie diese zu kommentieren. Stellen Sie stattdessen eine neue Frage.
Flodel
In both cases, 1:2 or c("a", "b") can be replaced by a pre-defined vector.Wenn ich einen vordefinierten Vektor wie diesen verwendet x[Vpredefined][is.na(x[Vpredefined])] <- 0habe, gibt es mir Fehler
Rohit Saluja
30

Bearbeiten 2020-06-15

data.tableErhält seit 1.12.4 (Okt. 2019) data.tablezwei Funktionen, um dies zu erleichtern: nafillund setnafill.

nafill arbeitet mit Spalten:

cols = c('a', 'b')
y[ , (cols) := lapply(.SD, nafill, fill=0), .SDcols = cols]

setnafill arbeitet mit Tabellen (die Ersetzungen erfolgen durch Referenz / an Ort und Stelle)

setnafill(y, cols=cols, fill=0)
# print y to show the effect
y[]

Dies ist auch effizienter als die anderen Optionen. siehe ?nafillfür mehr, die letzte Beobachtung-Vorträge (LOCF) und die nächste Beobachtungsdurch-Rückwärts (NOCB) Versionen von NAAnrechnungs für Zeitreihen.


Dies funktioniert für Ihre data.tableVersion:

for (col in c("a", "b")) y[is.na(get(col)), (col) := 0]

Alternativ können Sie, wie David Arenburg unten ausführt, Folgendes verwenden set(Nebeneffekt - Sie können es entweder auf data.frameoder verwenden data.table):

for (col in 1:2) set(x, which(is.na(x[[col]])), col, 0)
eddi
quelle
Danke dafür. Ich wollte nur 3 Jahre später wissen, ob es Möglichkeiten gibt, dies ohne for-Schleife zu tun? Ich kann mir vorstellen, dass dies vom data.table-Team präziser gestaltet worden wäre. Vielen Dank.
info_seekeR
1
@info_seekeR Ich kenne keinen prägnanteren Weg
eddi
Dies ist eine bessere Lösung als die ausgewählte Antwort von flodel. Der Ansatz von Flodel verwendet den Zuweisungsoperator <- und beinhaltet daher unnötiges Kopieren von Daten.
Michael
@MichaelChirico Haben Sie im ersten Teil Ihres Kommentars den Schritt hinzugefügt out <- x, um Missverständnisse mit dem x data.frame aus der Frage zu vermeiden? Andernfalls ist dies ein noch kürzerer Befehl: y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]Überspringen des Variablennamens 'out' und Verwendung von 'x'.
Yoann Pageaud
@ MichaelChirico Stimmt! Ich habe nafill () total vergessen
Yoann Pageaud
21

Aufbauend auf der tidyr::replace_na()Antwort von @Robert McDonald's gibt es hier einige dplyrOptionen, um zu steuern, welche Spalten die NAs ersetzen:

library(tidyverse)

# by column type:
x %>%
  mutate_if(is.numeric, ~replace_na(., 0))

# select columns defined in vars(col1, col2, ...):
x %>%
  mutate_at(vars(a, b, c), ~replace_na(., 0))

# all columns:
x %>%
  mutate_all(~replace_na(., 0))
sbha
quelle
1
Mit dieser Funktion erhalte ich den Fehler : Error in replace_na(., 0) : argument "value" is missing, with no default. Irgendwelche Vorschläge, was zu ändern ist?
Tim M. Schendzielorz
17

Dies ist jetzt in tidyr mit replace_na () trivial. Die Funktion scheint sowohl für data.tables als auch für data.frames zu funktionieren:

tidyr::replace_na(x, list(a=0, b=0))
Robert McDonald
quelle
2

Sie sind sich nicht sicher, ob dies präziser ist, aber diese Funktion findet und ermöglicht auch das Ersetzen von NAs (oder eines beliebigen Werts) in ausgewählten Spalten einer Datentabelle:

update.mat <- function(dt, cols, criteria) {
  require(data.table)
  x <- as.data.frame(which(criteria==TRUE, arr.ind = TRUE))
  y <- as.matrix(subset(x, x$col %in% which((names(dt) %in% cols), arr.ind = TRUE)))
  y
}

Um es anzuwenden:

y[update.mat(y, c("a", "b"), is.na(y))] <- 0

Die Funktion erstellt eine Matrix der ausgewählten Spalten und Zeilen (Zellkoordinaten), die die Eingabekriterien erfüllen (in diesem Fall is.na == TRUE).

Amy M.
quelle
1

Wir können es auf diese data.tableWeise mit tidyr::repalce_naFunktion und lösenlapply

library(data.table)
library(tidyr)
setDT(df)
df[,c("a","b","c"):=lapply(.SD,function(x) replace_na(x,0)),.SDcols=c("a","b","c")]

Auf diese Weise können wir auch Einfügespalten mit einer NAZeichenfolge lösen . Erst wir replace_na(x,""), dann können wir stringr::str_cSpalten kombinieren!

junger Chen
quelle
1
Vielen Dank für dieses Code-Snippet, das möglicherweise nur begrenzte und sofortige Hilfe bietet. Eine richtige Erklärung würde ihren langfristigen Wert erheblich verbessern, indem sie zeigt, warum dies eine gute Lösung für das Problem ist, und es für zukünftige Leser mit anderen, ähnlichen Fragen nützlicher machen. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, einschließlich der von Ihnen getroffenen Annahmen.
Bestimmte Leistung
0

Für eine bestimmte Spalte gibt es eine Alternative mit sapply

DF <- data.frame(A = letters[1:5],
             B = letters[6:10],
             C = c(2, 5, NA, 8, NA))

DF_NEW <- sapply(seq(1, nrow(DF)),
                    function(i) ifelse(is.na(DF[i,3]) ==
                                       TRUE,
                                       0,
                                       DF[i,3]))

DF[,3] <- DF_NEW
DF
Rafa
quelle
0

Es ist sehr praktisch mit {data.table} und {stringr}

library(data.table)
library(stringr)

x[, lapply(.SD, function(xx) {str_replace_na(xx, 0)})]

Zu Ihrer Information

Grec001
quelle
0

Ausgehend von der data.table y können Sie einfach schreiben:
y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]
Vergessen Sie nicht, library(data.table)bevor Sie ydiesen Befehl erstellen und ausführen .

Yoann Pageaud
quelle
-4

Das funktioniert gut für mich

DataTable DT = new DataTable();

DT = DT.AsEnumerable().Select(R =>
{
      R["Campo1"] = valor;
      return (R);
}).ToArray().CopyToDataTable();
Juanico Lasa
quelle
1
ist das R? sieht aus wie C #
Chris McKelt