I have a data.frame and some columns have NA values. I want to replace the NAs with zeros. How I do this?
我有一个数据,框架和一些列有NA值。我想用0代替na。我该如何去做呢?
592
See my comment in @gsk3 answer. A simple example:
请参见@gsk3的回复。一个简单的例子:
> 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
There's no need to apply apply
. =)
没有必要申请。=)
EDIT
编辑
You should also take a look at norm
package. It has a lot of nice features for missing data analysis. =)
您还应该看看规范包。它有很多很好的功能,可以忽略数据分析。=)
97
For a single vector:
为一个向量:
x <- c(1,2,NA,4,5)
x[is.na(x)] <- 0
For a data.frame, make a function out of the above, then apply
it to the columns.
对于一个数据。框架,从上面创建一个函数,然后将其应用到列中。
Please provide a reproducible example next time as detailed here:
请提供一个可重复的例子,下次详述如下:
How to make a great R reproducible example?
如何做一个伟大的R重现的例子?
90
The hybrid dplyr/Base R option: mutate_all(funs(replace(., is.na(.), 0))))
is more than twice as fast as the base R d[is.na(d)] <- 0
option. (please see benchmark analyses below.)
混合dplyr/Base R选项:mutate_all(funs)。,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(请参阅下面的基准分析。)
If you are struggling with massive dataframes, data.table
is the fastest option of all: 30% less time than dplyr, and 3 times faster than the Base R approaches. It also modifies the data in place, effectively allowing you to work with nearly twice as much of the data at once.
如果你正在与大规模的数据分析打交道,数据。表是最快的选择:比dplyr少30%,比基本R快3倍。它还可以对数据进行修改,有效地使您能够同时处理几乎两倍的数据。
Locationally:
区位:
mutate_at(c(5:10), funs(replace(., is.na(.), 0)))
mutate_at(vars(var5:var10), funs(replace(., is.na(.), 0)))
mutate_at(vars(contains("1")), funs(replace(., is.na(.), 0)))
contains()
, try ends_with()
,starts_with()
mutate_at(vars(matches("\\d{2}")), funs(replace(., is.na(.), 0)))
Conditionally:
(change just numeric (columns) and leave string (columns) alone.)
有条件地:(仅更改数字(列)并单独保留字符串(列)。
mutate_if(is.integer, funs(replace(., is.na(.), 0)))
mutate_if(is.numeric, funs(replace(., is.na(.), 0)))
mutate_if(is.character, funs(replace(., is.na(.), 0)))
# 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
library(tidyverse)
dplyr_if_else <- function(x) { mutate_all(x, funs(if_else(is.na(.), 0, .))) }
dplyr_coalesce <- function(x) { mutate_all(x, funs(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, funs(ifelse(is.na(.), 0, .))) }
hybrd.rplc_all <- function(x) { mutate_all(x, funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.idx<- function(x) { mutate_at(x, c(1:10), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.nse<- function(x) { mutate_at(x, vars(var1:var10), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.stw<- function(x) { mutate_at(x, vars(starts_with("var")), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.ctn<- function(x) { mutate_at(x, vars(contains("var")), funs(replace(., is.na(.), 0))) }
hybrd.rplc_at.mtc<- function(x) { mutate_at(x, vars(matches("\\d+")), funs(replace(., is.na(.), 0))) }
hybrd.rplc_if <- function(x) { mutate_if(x, is.numeric, funs(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) }
library(microbenchmark)
# 20% NA filled dataframe of 5 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)), 5e6*10, replace = TRUE),
dimnames = list(NULL, paste0("var", 1:10)),
ncol = 10))
# Running 250 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)),
baseR.sbst.rssgn = baseR.sbst.rssgn(copy(dfN)),
baseR.replace = baseR.replace(copy(dfN)),
dplyr_coalesce = dplyr_coalesce(copy(dfN)),
hybrd.rplc_at.nse= hybrd.rplc_at.nse(copy(dfN)),
hybrd.rplc_at.stw= hybrd.rplc_at.stw(copy(dfN)),
hybrd.rplc_at.ctn= hybrd.rplc_at.ctn(copy(dfN)),
hybrd.rplc_at.mtc= hybrd.rplc_at.mtc(copy(dfN)),
hybrd.rplc_at.idx= hybrd.rplc_at.idx(copy(dfN)),
hybrd.rplc_if = hybrd.rplc_if(copy(dfN)),
tidyr_replace_na = tidyr_replace_na(copy(dfN)),
baseR.for = baseR.for(copy(dfN)),
DT.for.set.nms = DT.for.set.nms(copy(dfN)),
DT.for.set.sqln = DT.for.set.sqln(copy(dfN)),
times = 250L
)
> perf_results Unit: milliseconds expr min lq mean median uq max neval hybrid.ifelse 5250.5259 5620.8650 5809.1808 5759.3997 5947.7942 6732.791 250 dplyr_if_else 3209.7406 3518.0314 3653.0317 3620.2955 3746.0293 4390.888 250 baseR.sbst.rssgn 1611.9227 1878.7401 1964.6385 1942.8873 2031.5681 2485.843 250 baseR.replace 1559.1494 1874.7377 1946.2971 1920.8077 2002.4825 2516.525 250 dplyr_coalesce 949.7511 1231.5150 1279.3015 1288.3425 1345.8662 1624.186 250 hybrd.rplc_at.nse 735.9949 871.1693 1016.5910 1064.5761 1104.9590 1361.868 250 hybrd.rplc_at.stw 704.4045 887.4796 1017.9110 1063.8001 1106.7748 1338.557 250 hybrd.rplc_at.ctn 723.9838 878.6088 1017.9983 1063.0406 1110.0857 1296.024 250 hybrd.rplc_at.mtc 686.2045 885.8028 1013.8293 1061.2727 1105.7117 1269.949 250 hybrd.rplc_at.idx 696.3159 880.7800 1003.6186 1038.8271 1083.1932 1309.635 250 hybrd.rplc_if 705.9907 889.7381 1000.0113 1036.3963 1083.3728 1338.190 250 tidyr_replace_na 680.4478 973.1395 978.2678 1003.9797 1051.2624 1294.376 250 baseR.for 670.7897 965.6312 983.5775 1001.5229 1052.5946 1206.023 250 DT.for.set.nms 496.8031 569.7471 695.4339 623.1086 861.1918 1067.640 250 DT.for.set.sqln 500.9945 567.2522 671.4158 623.1454 764.9744 1033.463 250
# adjust the margins to prepare for better boxplot printing
par(mar=c(8,5,1,1) + 0.1)
# generate boxplot
boxplot(opN, las = 2, xlab = "", ylab = "log(time)[milliseconds]")
qplot(y=time/10^9, data=opN, colour=expr) +
labs(y = "log10 Scaled Elapsed Time per Trial (secs)", x = "Trial Number") +
scale_y_log10(breaks=c(1, 2, 4))
When the datasets get larger, Tidyr''s replace_na
had historically pulled out in front. With the current collection of 50M data points to run through, it performs almost exactly as well as a Base R For Loop. I am curious to see what happens for different sized dataframes.
当数据集变得更大时,Tidyr的replace_na在历史上就被拉到了前面。通过当前收集的50M数据点来运行,它的执行几乎和以R为基础的循环一样好。我很想知道不同尺寸的dataframes会发生什么情况。
Additional examples for the mutate
and summarize
_at
and _all
function variants can be found here: https://rdrr.io/cran/dplyr/man/summarise_all.html Additionally, I found helpful demonstrations and collections of examples here: https://blog.exploratory.io/dplyr-0-5-is-awesome-heres-why-be095fd4eb8a
在这里可以找到mutate和汇总_at和_all函数变体的其他示例:https://rdrr.io/cran/dplyr/man/summary se_all。另外,我还发现了一些有用的演示和示例集合:https://blog.exploratory.io/dplyr-0-5-is- her -why-be095fd4eb8a。
With special thanks to:
特别感谢:
local()
, and (with Frank's patient help, too) the role that silent coercion plays in speeding up many of these approaches. coalesce()
function in and update the analysis.data.table
functions well enough to finally include them in the lineup.(Of course, please reach over and give them upvotes, too if you find those approaches useful.)
(当然,如果你觉得这些方法有用的话,请伸出手给他们投票。)
Note on my use of Numerics: If you do have a pure integer dataset, all of your functions will run faster. Please see alexiz_laz's work for more information. IRL, I can't recall encountering a data set containing more than 10-15% integers, so I am running these tests on fully numeric dataframes.
注意我对数字的使用:如果您有一个纯整数数据集,那么所有的函数都将运行得更快。请参阅alexiz_laz的工作以获得更多信息。IRL,我不记得遇到一个包含超过10-15%整数的数据集,所以我在全数字的dataframes上运行这些测试。
57
dplyr example:
dplyr例子:
library(dplyr)
df1 <- df1 %>%
mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))
Note: This works per selected column, if we need to do this for all column, see @reidjax's answer using mutate_each.
注意:如果我们需要为所有列执行这个操作,那么每个选中的列都可以使用这个方法,请使用mutate_each来查看@reidjax的答案。
40
I know the question is already answered, but doing it this way might be more useful to some:
我知道这个问题已经回答了,但是这样做可能对一些人更有用:
Define this function:
定义这个函数:
na.zero <- function (x) {
x[is.na(x)] <- 0
return(x)
}
Now whenever you need to convert NA's in a vector to zero's you can do:
现在,当你需要将NA在向量中转换为0时,你可以这样做:
na.zero(some.vector)
38
If we are trying to replace NA
s when exporting, for example when writing to csv, then we can use:
如果我们在导出时试图替换NAs,例如在写入csv时,我们可以使用:
write.csv(data, "data.csv", na = "0")
18
More general approach of using replace()
in matrix or vector to replace NA
to 0
在矩阵或向量中使用replace()的更一般方法将NA替换为0。
For example:
例如:
> x <- c(1,2,NA,NA,1,1)
> x1 <- replace(x,is.na(x),0)
> x1
[1] 1 2 0 0 1 1
This is also an alternative to using ifelse()
in dplyr
这也是在dplyr中使用ifelse()的一种替代方法。
df = data.frame(col = c(1,2,NA,NA,1,1))
df <- df %>%
mutate(col = replace(col,is.na(col),0))
14
With dplyr
0.5.0, you can use coalesce
function which can be easily integrated into %>%
pipeline by doing coalesce(vec, 0)
. This replaces all NAs in vec
with 0:
使用dplyr 0.5.0,您可以使用合并函数,通过合并(vec, 0)可以很容易地集成到%>%管道中。
Say we have a data frame with NA
s:
假设我们有一个带有NAs的数据帧:
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
8
If you want to replace NAs in factor variables, this might be useful:
如果你想用因子变量替换NAs,这可能有用:
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")
It transforms a factor-vector into a numeric vector and adds another artifical numeric factor level, which is then transformed back to a factor-vector with one extra "NA-level" of your choice.
它将一个因子向量转换成一个数字向量,并添加另一个人工数字因子水平,然后将其转换回一个因子向量,并在选择的另一个“NA-level”中进行转换。
7
Another example using imputeTS package:
另一个使用冒名包的例子:
library(imputeTS)
na.replace(yourDataframe, 0)
6
Would've commented on @ianmunoz's post but I don't have enough reputation. You can combine dplyr
's mutate_each
and replace
to take care of the NA
to 0
replacement. Using the dataframe from @aL3xa's answer...
我会评论@ianmunoz的帖子,但我没有足够的声誉。你可以把dplyr的mutate_each和replace替换为take care of the NA to 0 replacement。从@aL3xa的答案中使用dataframe…
> 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
We're using standard evaluation (SE) here which is why we need the underscore on "funs_
." We also use lazyeval
's interp
/~
and the .
references "everything we are working with", i.e. the data frame. Now there are zeros!
我们使用的是标准评估(SE),这就是为什么我们需要“funs_”的下划线。我们还使用了lazyeval的interp/~和。引用“我们正在处理的所有内容”,即数据框架。现在是零!
4
You can use replace()
您可以使用替代()
For example:
例如:
> 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
3
Another dplyr
pipe compatible option with tidyr
method replace_na
that works for several columns:
另一个与tidyrmethod replace_na兼容的dplyr管道兼容选项,适用于多个列:
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)
You can easily restrict to e.g. numeric columns:
你可以很容易地限制数字列:
d$str <- c("string", NA)
myList <- myList[sapply(d, is.numeric)]
df <- d %>% replace_na(myList)
3
This simple function extracted from Datacamp could help:
从Datacamp中提取的这个简单函数可以帮助:
replace_missings <- function(x, replacement) {
is_miss <- is.na(x)
x[is_miss] <- replacement
message(sum(is_miss), " missings replaced by the value ", replacement)
x
}
Then
然后
replace_missings(df, replacement = 0)