我有一个数据框,其中一些列具有NA
值。
我该如何用零替换这些NA
值?
请查看@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
无需应用apply
。=)
编辑
您还应该查看norm
软件包。它具有许多用于缺失数据分析的不错功能。=)
df[19:28][is.na(df[19:28])] <- 0
。 - jtdouddplyr混合选项现在比基本R子集重新分配快30%。在一个1亿数据点的数据框中,mutate_all(~replace(., is.na(.), 0))
比基本R d[is.na(d)] <- 0
选项快半秒钟。需要特别避免使用 ifelse()
或 if_else()
。 (完整的600次试验分析耗时超过4.5小时,主要是因为包括了这些方法。)请参见下面的基准分析获取完整结果。
如果您正在处理大型数据框,则data.table
是所有选项中最快的:比标准Base R方法快40%。它还可以直接修改数据,有效地使您能够一次处理将近两倍的数据。
位置:
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))
ends_with()
,starts_with()
替换 contains()
mutate_at(vars(matches("\\d{2}")), ~replace(., is.na(.), 0))
条件:
(仅更改单个类型并保留其他类型不变。)
mutate_if(is.integer, ~replace(., is.na(.), 0))
mutate_if(is.numeric, ~replace(., is.na(.), 0))
mutate_if(is.character, ~replace(., is.na(.), 0))
##完整分析 -
更新为 dplyr 0.8.0:函数使用 purrr 格式的 ~
符号,替换已弃用的 funs()
参数。
###测试的方法:
# 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(
hybrd.ifelse = hybrd.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)))
当数据集变得更大时,Tidyr 的 replace_na
函数一直处于领先地位。在当前 1 亿个数据点的集合中运行时,它的表现几乎与一个 Base R For Loop 相同。我很想看看不同大小的数据框会发生什么。
有关 mutate
和 summarize
_at
和 _all
函数变体的其他示例可以在这里找到:https://rdrr.io/cran/dplyr/man/summarise_all.html 此外,我在这里找到了有用的演示和示例集:https://blog.exploratory.io/dplyr-0-5-is-awesome-heres-why-be095fd4eb8a
特别感谢:
local()
的用法,并在 Frank 的耐心帮助下,加快了许多方法的速度。coalesce()
函数并更新分析的提示。data.table
函数,以便最终将它们包括在内。is.numeric()
到底测试了什么。(当然,如果你认为这些方法有用,请给它们点赞。)
我的数字使用说明:如果你有一个纯整数数据集,所有的函数都将运行得更快。更多信息请参见alexiz_laz的工作。在现实生活中,我记不起来遇到过超过10-15%整数的数据集,因此我正在对完全数值化的数据帧进行这些测试。使用的硬件:3.9 GHz CPU with 24 GB RAM
z <- c(1,2,3); z[2] <- 0L; str(z)
仍然是数字类型。 - Frankcoalesce()
选项并重新运行了所有时间。感谢您的提醒更新。 - leerssejmutate_at
和mutate_all
函数,可以使用以下代码来替代:function(x) { mutate(across(x, ~replace_na(., 0))) }
,该代码的作用是将数据框某些列中的缺失值替换成0。 - Jeff Parker对于单个向量:
x <- c(1,2,NA,4,5)
x[is.na(x)] <- 0
针对一个数据框,将上述内容制作成一个函数,然后使用 apply
函数应用于列。
下次请提供可复现的示例,详见:
is.na
是一个通用函数,它有适用于 data.frame
类型对象的方法。因此,这个函数也可以用于处理 data.frame
对象! - aL3xamethods(is.na)
时,我就像“哇?!?”我喜欢这样的事情发生!=) - aL3xalibrary(dplyr)
df1 <- df1 %>%
mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))
注意: 这适用于所选列,如果我们需要对所有列进行操作,请参见 @reidjax 的答案,使用mutate_each。
如果我们在导出数据,例如写入csv时想要替换NA
,那么可以使用以下方法:
write.csv(data, "data.csv", na = "0")
您也可以使用 tidyr::replace_na
。
library(tidyr)
df <- df %>% mutate_all(funs(replace_na(.,0)))
编辑(dplyr > 1.0.0):
df %>% mutate(across(everything(), .fns = ~replace_na(.,0)))
mutate_*
verbs are now superseded by across()
- Ömer Anreplace(is.na(.), 0)
函数包装在 mutate()
中。为什么不能直接将其输入到管道中? - Faustin Gashakambamutate
可以创建或替换变量。 - Juliendplyr 1.1.0
开始,您应该这样编写替换
mutate(data, across(.cols = everything(), \(x) replace_na(x, 0)))
- ha-pu〜
),并提供了轻微的性能提升。 - LMc~
),并且可以提供轻微的性能提升。 - undefined我知道这个问题已经有答案了,但是按照这种方式做可能对某些人更有用:
定义这个函数:
na.zero <- function (x) {
x[is.na(x)] <- 0
return(x)
}
现在,每当您需要将向量中的 NA 转换为 0 时,可以执行以下操作:
na.zero(some.vector)
使用replace()
在矩阵或向量中替换NA
为0
的更通用方法。
例如:
> x <- c(1,2,NA,NA,1,1)
> x1 <- replace(x,is.na(x),0)
> x1
[1] 1 2 0 0 1 1
这也是在 dplyr
中使用 ifelse()
的替代方法。
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")
- Climbs_lika_Spyderwhich
,你可以使用 x1 <- replace(x,is.na(x),1)
。 - lmoNA
替换为0
,而这个replace()
函数既最有效,又最简单。 - Gerry使用 dplyr
0.5.0 版本,您可以使用 coalesce
函数,并通过执行 coalesce(vec, 0)
轻松将其集成到 %>%
管道中。这将用 0 替换 vec
中的所有 NAs:
假设我们有一个带有 NA
的数据框:
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
mutate(across(where(is.character), ~ coalesce(.x, 0)))
- LMcmutate(across(where(is.character), ~ coalesce(.x, 0)))
- undefined要替换数据框中的所有NA值,您可以使用:
df %>% replace(is.na(.), 0)