Ich habe einen Datenrahmen und einige Spalten haben NA
Werte.
Wie ersetze ich diese NA
Werte durch Nullen?
Ich habe einen Datenrahmen und einige Spalten haben NA
Werte.
Wie ersetze ich diese NA
Werte durch Nullen?
Antworten:
Siehe meinen Kommentar in @ gsk3 Antwort. Ein einfaches Beispiel:
> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
> d <- as.data.frame(m)
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 3 NA 3 7 6 6 10 6 5
2 9 8 9 5 10 NA 2 1 7 2
3 1 1 6 3 6 NA 1 4 1 6
4 NA 4 NA 7 10 2 NA 4 1 8
5 1 2 4 NA 2 6 2 6 7 4
6 NA 3 NA NA 10 2 1 10 8 4
7 4 4 9 10 9 8 9 4 10 NA
8 5 8 3 2 1 4 5 9 4 7
9 3 9 10 1 9 9 10 5 3 3
10 4 2 2 5 NA 9 7 2 5 5
> d[is.na(d)] <- 0
> d
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 3 0 3 7 6 6 10 6 5
2 9 8 9 5 10 0 2 1 7 2
3 1 1 6 3 6 0 1 4 1 6
4 0 4 0 7 10 2 0 4 1 8
5 1 2 4 0 2 6 2 6 7 4
6 0 3 0 0 10 2 1 10 8 4
7 4 4 9 10 9 8 9 4 10 0
8 5 8 3 2 1 4 5 9 4 7
9 3 9 10 1 9 9 10 5 3 3
10 4 2 2 5 0 9 7 2 5 5
Es besteht keine Notwendigkeit, sich zu bewerben apply
. =)
BEARBEITEN
Sie sollten sich auch das norm
Paket ansehen . Es hat viele nette Funktionen für die Analyse fehlender Daten. =)
df[19:28][is.na(df[19:28])] <- 0
Die mit dplyr hybridisierten Optionen sind jetzt etwa 30% schneller als die Neuzuweisung der Base R-Teilmenge. Auf einem 100M-Datenpunkt mutate_all(~replace(., is.na(.), 0))
läuft der Datenrahmen eine halbe Sekunde schneller als die Basis-R- d[is.na(d)] <- 0
Option. Was man konkret vermeiden möchte, ist die Verwendung eines ifelse()
oder eines if_else()
. (Die vollständige 600-Studienanalyse dauerte mehr als 4,5 Stunden, hauptsächlich aufgrund der Einbeziehung dieser Ansätze.) Die vollständigen Ergebnisse finden Sie in den folgenden Benchmark-Analysen.
Wenn Sie mit massivem Datenrahmen zu kämpfen hat , data.table
ist die schnellste Möglichkeit , alle: 40% schneller als der Standard - Base - R - Ansatz. Außerdem werden die vorhandenen Daten geändert, sodass Sie effektiv mit fast doppelt so vielen Daten gleichzeitig arbeiten können.
Standortlich:
mutate_at(c(5:10), ~replace(., is.na(.), 0))
mutate_at(vars(var5:var10), ~replace(., is.na(.), 0))
mutate_at(vars(contains("1")), ~replace(., is.na(.), 0))
contains()
, versuchen Sie ends_with()
,starts_with()
mutate_at(vars(matches("\\d{2}")), ~replace(., is.na(.), 0))
Bedingt:
(Nur einen Typ ändern und andere Typen in Ruhe lassen.)
mutate_if(is.integer, ~replace(., is.na(.), 0))
mutate_if(is.numeric, ~replace(., is.na(.), 0))
mutate_if(is.character, ~replace(., is.na(.), 0))
Aktualisiert für dplyr 0.8.0: Funktionen verwenden ~
Symbole im Purrr-Format : Ersetzen veralteter funs()
Argumente.
# Base R:
baseR.sbst.rssgn <- function(x) { x[is.na(x)] <- 0; x }
baseR.replace <- function(x) { replace(x, is.na(x), 0) }
baseR.for <- function(x) { for(j in 1:ncol(x))
x[[j]][is.na(x[[j]])] = 0 }
# tidyverse
## dplyr
dplyr_if_else <- function(x) { mutate_all(x, ~if_else(is.na(.), 0, .)) }
dplyr_coalesce <- function(x) { mutate_all(x, ~coalesce(., 0)) }
## tidyr
tidyr_replace_na <- function(x) { replace_na(x, as.list(setNames(rep(0, 10), as.list(c(paste0("var", 1:10)))))) }
## hybrid
hybrd.ifelse <- function(x) { mutate_all(x, ~ifelse(is.na(.), 0, .)) }
hybrd.replace_na <- function(x) { mutate_all(x, ~replace_na(., 0)) }
hybrd.replace <- function(x) { mutate_all(x, ~replace(., is.na(.), 0)) }
hybrd.rplc_at.idx<- function(x) { mutate_at(x, c(1:10), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.nse<- function(x) { mutate_at(x, vars(var1:var10), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.stw<- function(x) { mutate_at(x, vars(starts_with("var")), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.ctn<- function(x) { mutate_at(x, vars(contains("var")), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.mtc<- function(x) { mutate_at(x, vars(matches("\\d+")), ~replace(., is.na(.), 0)) }
hybrd.rplc_if <- function(x) { mutate_if(x, is.numeric, ~replace(., is.na(.), 0)) }
# data.table
library(data.table)
DT.for.set.nms <- function(x) { for (j in names(x))
set(x,which(is.na(x[[j]])),j,0) }
DT.for.set.sqln <- function(x) { for (j in seq_len(ncol(x)))
set(x,which(is.na(x[[j]])),j,0) }
DT.nafill <- function(x) { nafill(df, fill=0)}
DT.setnafill <- function(x) { setnafill(df, fill=0)}
library(microbenchmark)
# 20% NA filled dataframe of 10 Million rows and 10 columns
set.seed(42) # to recreate the exact dataframe
dfN <- as.data.frame(matrix(sample(c(NA, as.numeric(1:4)), 1e7*10, replace = TRUE),
dimnames = list(NULL, paste0("var", 1:10)),
ncol = 10))
# Running 600 trials with each replacement method
# (the functions are excecuted locally - so that the original dataframe remains unmodified in all cases)
perf_results <- microbenchmark(
hybrid.ifelse = hybrid.ifelse(copy(dfN)),
dplyr_if_else = dplyr_if_else(copy(dfN)),
hybrd.replace_na = hybrd.replace_na(copy(dfN)),
baseR.sbst.rssgn = baseR.sbst.rssgn(copy(dfN)),
baseR.replace = baseR.replace(copy(dfN)),
dplyr_coalesce = dplyr_coalesce(copy(dfN)),
tidyr_replace_na = tidyr_replace_na(copy(dfN)),
hybrd.replace = hybrd.replace(copy(dfN)),
hybrd.rplc_at.ctn= hybrd.rplc_at.ctn(copy(dfN)),
hybrd.rplc_at.nse= hybrd.rplc_at.nse(copy(dfN)),
baseR.for = baseR.for(copy(dfN)),
hybrd.rplc_at.idx= hybrd.rplc_at.idx(copy(dfN)),
DT.for.set.nms = DT.for.set.nms(copy(dfN)),
DT.for.set.sqln = DT.for.set.sqln(copy(dfN)),
times = 600L
)
> print(perf_results) Unit: milliseconds expr min lq mean median uq max neval hybrd.ifelse 6171.0439 6339.7046 6425.221 6407.397 6496.992 7052.851 600 dplyr_if_else 3737.4954 3877.0983 3953.857 3946.024 4023.301 4539.428 600 hybrd.replace_na 1497.8653 1706.1119 1748.464 1745.282 1789.804 2127.166 600 baseR.sbst.rssgn 1480.5098 1686.1581 1730.006 1728.477 1772.951 2010.215 600 baseR.replace 1457.4016 1681.5583 1725.481 1722.069 1766.916 2089.627 600 dplyr_coalesce 1227.6150 1483.3520 1524.245 1519.454 1561.488 1996.859 600 tidyr_replace_na 1248.3292 1473.1707 1521.889 1520.108 1570.382 1995.768 600 hybrd.replace 913.1865 1197.3133 1233.336 1238.747 1276.141 1438.646 600 hybrd.rplc_at.ctn 916.9339 1192.9885 1224.733 1227.628 1268.644 1466.085 600 hybrd.rplc_at.nse 919.0270 1191.0541 1228.749 1228.635 1275.103 2882.040 600 baseR.for 869.3169 1180.8311 1216.958 1224.407 1264.737 1459.726 600 hybrd.rplc_at.idx 839.8915 1189.7465 1223.326 1228.329 1266.375 1565.794 600 DT.for.set.nms 761.6086 915.8166 1015.457 1001.772 1106.315 1363.044 600 DT.for.set.sqln 787.3535 918.8733 1017.812 1002.042 1122.474 1321.860 600
ggplot(perf_results, aes(x=expr, y=time/10^9)) +
geom_boxplot() +
xlab('Expression') +
ylab('Elapsed Time (Seconds)') +
scale_y_continuous(breaks = seq(0,7,1)) +
coord_flip()
qplot(y=time/10^9, data=perf_results, colour=expr) +
labs(y = "log10 Scaled Elapsed Time per Trial (secs)", x = "Trial Number") +
coord_cartesian(ylim = c(0.75, 7.5)) +
scale_y_log10(breaks=c(0.75, 0.875, 1, 1.25, 1.5, 1.75, seq(2, 7.5)))
Wenn die Datensätze größer werden, hat sich Tidyr 's replace_na
historisch nach vorne zurückgezogen. Mit der aktuellen Sammlung von 100 Millionen Datenpunkten, die durchlaufen werden müssen, ist die Leistung fast genauso gut wie bei einer Base R For Loop. Ich bin gespannt, was bei unterschiedlich großen Datenrahmen passiert.
Weitere Beispiele für die Varianten mutate
und summarize
_at
und _all
finden Sie hier: https://rdrr.io/cran/dplyr/man/summarise_all.html
Außerdem habe ich hier hilfreiche Demonstrationen und Sammlungen von Beispielen gefunden: https: //blog.exploratory. io / dplyr-0-5-is-awesome-heres-why-be095fd4eb8a
Mit besonderem Dank an:
local()
und (auch mit Franks geduldiger Hilfe) die Rolle zu verstehen, die stiller Zwang bei der Beschleunigung vieler dieser Ansätze spielt. coalesce()
Funktion hinzuzufügen und die Analyse zu aktualisieren.data.table
Funktionen gut genug herauszufinden, um sie endlich in die Aufstellung aufzunehmen.is.numeric()
wirklich testet.(Natürlich greifen Sie bitte zu ihnen und geben Sie ihnen auch Stimmen, wenn Sie diese Ansätze nützlich finden.)
Hinweis zu meiner Verwendung von Numerics: Wenn Sie ein reines Integer-Dataset haben, werden alle Ihre Funktionen schneller ausgeführt. Bitte beachten Sie alexiz_laz Arbeit für weitere Informationen. IRL, ich kann mich nicht erinnern, auf einen Datensatz gestoßen zu sein, der mehr als 10-15% Ganzzahlen enthält. Daher führe ich diese Tests für vollständig numerische Datenrahmen aus.
Verwendete Hardware 3,9 GHz CPU mit 24 GB RAM
df1[j][is.na(df1[j])] = 0
ist falsch, sollte seindf1[[j]][is.na(df1[[j]])] = 0
forLp_Sbst
scheint nicht so, als ob jemand darüber nachdenken sollte, sich ihm zu nähernforLp_smplfSbst
coalesce()
Option hinzugefügt und immer wieder ausgeführt. Vielen Dank für den Anstoß zum Update.
Für einen einzelnen Vektor:
x <- c(1,2,NA,4,5)
x[is.na(x)] <- 0
Machen Sie für einen data.frame eine Funktion aus dem oben genannten und dann apply
zu den Spalten.
Bitte geben Sie beim nächsten Mal ein reproduzierbares Beispiel an, wie hier beschrieben:
is.na
ist eine generische Funktion und verfügt über Methoden für Objekte der data.frame
Klasse. also wird dieser auch auf data.frame
s funktionieren !
methods(is.na)
zum ersten Mal rannte , war ich wie was?!? . Ich liebe es, wenn so etwas passiert! =)
dplyr Beispiel:
library(dplyr)
df1 <- df1 %>%
mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))
Hinweis: Dies funktioniert für jede ausgewählte Spalte. Wenn dies für alle Spalten erforderlich ist , lesen Sie die Antwort von @reidjax mit mutate_each .
Wenn wir versuchen, NA
s beim Exportieren zu ersetzen , beispielsweise beim Schreiben in csv, können wir Folgendes verwenden:
write.csv(data, "data.csv", na = "0")
Ich weiß, dass die Frage bereits beantwortet ist, aber auf diese Weise könnte es für einige nützlicher sein:
Definieren Sie diese Funktion:
na.zero <- function (x) {
x[is.na(x)] <- 0
return(x)
}
Wann immer Sie NAs in einem Vektor in Nullen konvertieren müssen, können Sie Folgendes tun:
na.zero(some.vector)
Mit dplyr
0.5.0 können Sie coalesce
Funktionen verwenden, die auf einfache Weise in die %>%
Pipeline integriert werden können coalesce(vec, 0)
. Dies ersetzt alle NAs vec
durch 0:
Angenommen, wir haben einen Datenrahmen mit NA
s:
library(dplyr)
df <- data.frame(v = c(1, 2, 3, NA, 5, 6, 8))
df
# v
# 1 1
# 2 2
# 3 3
# 4 NA
# 5 5
# 6 6
# 7 8
df %>% mutate(v = coalesce(v, 0))
# v
# 1 1
# 2 2
# 3 3
# 4 0
# 5 5
# 6 6
# 7 8
Allgemeineren Ansatz der Verwendung replace()
in Matrix oder Vektor ersetzen NA
zu0
Zum Beispiel:
> x <- c(1,2,NA,NA,1,1)
> x1 <- replace(x,is.na(x),0)
> x1
[1] 1 2 0 0 1 1
Dies ist auch eine Alternative zur Verwendung ifelse()
indplyr
df = data.frame(col = c(1,2,NA,NA,1,1))
df <- df %>%
mutate(col = replace(col,is.na(col),0))
levels(A$x) <- append(levels(A$x), "notAnswered") A$x <- replace(A$x,which(is.na(A$x)),"notAnswered")
which
wird hier nicht benötigt, können Sie verwenden x1 <- replace(x,is.na(x),1)
.
NA
sie 0
in nur einer bestimmten Spalte in einem großen Datenrahmen zu ersetzen , und diese Funktion replace()
hat am effektivsten und gleichzeitig am einfachsten funktioniert .
Wenn Sie NAs in Faktorvariablen ersetzen möchten, kann dies hilfreich sein:
n <- length(levels(data.vector))+1
data.vector <- as.numeric(data.vector)
data.vector[is.na(data.vector)] <- n
data.vector <- as.factor(data.vector)
levels(data.vector) <- c("level1","level2",...,"leveln", "NAlevel")
Es transformiert einen Faktorvektor in einen numerischen Vektor und fügt eine weitere künstliche numerische Faktorebene hinzu, die dann mit einer zusätzlichen "NA-Ebene" Ihrer Wahl in einen Faktorvektor zurücktransformiert wird.
Hätte den Beitrag von @ ianmunoz kommentiert, aber ich habe nicht genug Ruf. Sie können kombinieren dplyr
‚s mutate_each
und replace
Betreuung von nehmen , NA
um 0
Ersatz. Verwenden des Datenrahmens aus der Antwort von @ aL3xa ...
> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
> d <- as.data.frame(m)
> d
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 8 1 9 6 9 NA 8 9 8
2 8 3 6 8 2 1 NA NA 6 3
3 6 6 3 NA 2 NA NA 5 7 7
4 10 6 1 1 7 9 1 10 3 10
5 10 6 7 10 10 3 2 5 4 6
6 2 4 1 5 7 NA NA 8 4 4
7 7 2 3 1 4 10 NA 8 7 7
8 9 5 8 10 5 3 5 8 3 2
9 9 1 8 7 6 5 NA NA 6 7
10 6 10 8 7 1 1 2 2 5 7
> d %>% mutate_each( funs_( interp( ~replace(., is.na(.),0) ) ) )
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 8 1 9 6 9 0 8 9 8
2 8 3 6 8 2 1 0 0 6 3
3 6 6 3 0 2 0 0 5 7 7
4 10 6 1 1 7 9 1 10 3 10
5 10 6 7 10 10 3 2 5 4 6
6 2 4 1 5 7 0 0 8 4 4
7 7 2 3 1 4 10 0 8 7 7
8 9 5 8 10 5 3 5 8 3 2
9 9 1 8 7 6 5 0 0 6 7
10 6 10 8 7 1 1 2 2 5 7
Wir verwenden hier die Standardbewertung (SE), weshalb wir den Unterstrich " funs_
." Wir verwenden auch lazyeval
's interp
/ ~
und die .
Referenzen "alles, mit dem wir arbeiten", dh den Datenrahmen. Jetzt gibt es Nullen!
Sie können verwenden replace()
Zum Beispiel:
> x <- c(-1,0,1,0,NA,0,1,1)
> x1 <- replace(x,5,1)
> x1
[1] -1 0 1 0 1 0 1 1
> x1 <- replace(x,5,mean(x,na.rm=T))
> x1
[1] -1.00 0.00 1.00 0.00 0.29 0.00 1.00 1.00
NA
s in Ihrem Vektor kennen. Es ist gut für kleine Vektoren wie in Ihrem Beispiel.
x1 <- replace(x,is.na(x),1)
funktioniert ohne explizite Auflistung der Indexwerte.
Eine weitere dplyr
Pipe-kompatible Option mit einer tidyr
Methode replace_na
, die für mehrere Spalten funktioniert:
require(dplyr)
require(tidyr)
m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
d <- as.data.frame(m)
myList <- setNames(lapply(vector("list", ncol(d)), function(x) x <- 0), names(d))
df <- d %>% replace_na(myList)
Sie können sich leicht auf z. B. numerische Spalten beschränken:
d$str <- c("string", NA)
myList <- myList[sapply(d, is.numeric)]
df <- d %>% replace_na(myList)
Die dafür vorgesehene Funktion ( nafill
/ setnafill
) ist in der aktuellen data.table
Version enthalten
install.packages("data.table", repos="https://Rdatatable.gitlab.io/data.table")
library(data.table)
ans_df = nafill(df, fill=0)
setnafill(df, fill=0) # this one updates in-place
So ersetzen Sie alle NAs in einem Datenrahmen:
df %>% replace(is.na(.), 0)
Wenn Sie nach dem Ändern der NAs in einer bestimmten Spalte in diesem Fall einen neuen Namen zuweisen möchten, können Sie dies auch tun
my.data.frame$the.new.column.name <- ifelse(is.na(my.data.frame$V3),0,1)