我有一个数据框,有些列有 NA 值 .
NA
如何用零替换这些 NA 值?
如果我们在导出时尝试替换 NA ,例如在写入csv时,我们可以使用:
write.csv(data, "data.csv", na = "0")
使用 dplyr 0.5.0,您可以使用 coalesce 函数,通过执行 coalesce(vec, 0) 可以轻松地将其集成到 %>% 管道中 . 这将取代 vec 中的所有NAs为0:
dplyr
coalesce
coalesce(vec, 0)
%>%
vec
假设我们有一个 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
在@ 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 . =)
apply
EDIT
您还应该看一下 norm 包 . 它有很多很好的功能,可用于缺少数据分析 . =)
norm
在矩阵或向量中使用 replace() 替换 NA 到 0 的更一般方法
replace()
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() 的替代方法
ifelse()
df = data.frame(col = c(1,2,NA,NA,1,1)) df <- df %>% mutate(col = replace(col,is.na(col),0))
你可以使用 replace()
> 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
从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 }
然后
replace_missings(df, replacement = 0)
另一个使用 imputeTS 包的例子:
library(imputeTS) na.replace(yourDataframe, 0)
另一个 dplyr 管道兼容选项, tidyr 方法 replace_na 适用于多个列:
tidyr
replace_na
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)
您可以轻松限制为例如数字列:
d$str <- c("string", NA) myList <- myList[sapply(d, is.numeric)] df <- d %>% replace_na(myList)
've commented on @ianmunoz'的帖子,但我没有足够的声誉 . 你可以组合 dplyr 的 mutate_each 和 replace 来处理 NA 到 0 的替换 . 使用来自@ aL3xa答案的数据框...
mutate_each
replace
> 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
我们在这里使用标准评估(SE),这就是为什么我们需要“ funs_ ”的下划线 . 我们还使用 lazyeval 的 interp / ~ 和 . 引用"everything we are working with",即数据帧 . 现在有零!
funs_
lazyeval
interp
~
.
对于单个向量:
x <- c(1,2,NA,4,5) x[is.na(x)] <- 0
对于data.frame,从上面创建一个函数,然后 apply 到列 .
请在下次详细说明下提供可重现的示例:
How to make a great R reproducible example?
如果要在因子变量中替换NA,这可能很有用:
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")
它将因子矢量转换为数字矢量,并添加另一个人工数字因子级别,然后将其转换回因子矢量,并选择一个额外的“NA级别” .
混合dplyr / Base R选项: mutate_all(funs(replace(., is.na(.), 0)))) 的速度是基本R d[is.na(d)] <- 0 选项的两倍多 . (请参阅下面的基准分析 . )
mutate_all(funs(replace(., is.na(.), 0))))
d[is.na(d)] <- 0
如果您正在努力应对海量数据帧, data.table 是最快的选择:比dplyr少30%的时间,比Base R接近3倍 . 它还可以修改数据,有效地允许您同时处理几乎两倍的数据 .
data.table
Locationally:
index mutate_at(c(5:10), funs(replace(., is.na(.), 0)))
mutate_at(c(5:10), funs(replace(., is.na(.), 0)))
直接参考 mutate_at(vars(var5:var10), 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)))
mutate_at(vars(contains("1")), funs(replace(., is.na(.), 0)))
或代替 contains() ,试试 ends_with() , starts_with()
contains()
ends_with()
starts_with()
模式匹配 mutate_at(vars(matches("\\d{2}")), funs(replace(., is.na(.), 0)))
mutate_at(vars(matches("\\d{2}")), funs(replace(., is.na(.), 0)))
Conditionally:(仅更改数字(列)并单独保留字符串(列) . )
整数 mutate_if(is.integer, funs(replace(., is.na(.), 0)))
mutate_if(is.integer, funs(replace(., is.na(.), 0)))
双打 mutate_if(is.numeric, funs(replace(., is.na(.), 0)))
mutate_if(is.numeric, funs(replace(., is.na(.), 0)))
字符串 mutate_if(is.character, 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单位:毫秒expr min lq mean中位数uq max nevalhybrid.ifelse 5250.5259 5620.8650 5809.1808 5759.3997 5947.7942 6732.791 250dplyr_if_else 3209.7406 3518.0314 3653.0317 3620.2955 3746.0293 4390.888 250baseR.sbst.rssgn 1611.9227 1878.7401 1964.6385 1942.8873 2031.5681 2485.843 250baseR.replace 1559.1494 1874.7377 1946.2971 1920.8077 2002.4825 2516.525 250dplyr_coalesce 949.7511 1231.5150 1279.3015 1288.3425 1345.8662 1624.186 250hybrd.rplc_at.nse 735.9949 871.1693 1016.5910 1064.5761 1104.9590 1361.868 250hybrd.rplc_at.stw 704.4045 887.4796 1017.9110 1063.8001 1106.7748 1338.557 250hybrd.rplc_at.ctn 723.9838 878.6088 1017.9983 1063.0406 1110.0857 1296.024 250hybrd.rplc_at.mtc 686.2045 885.8028 1013.8293 1061.2727 1105.7117 1269.949 250hybrd.rplc_at.idx 696.3159 880.7800 1003.6186 1038.8271 1083.1932 1309.635 250hybrd.rplc_if 705.9907 889.7381 1000.0113 1036.3963 1083.3728 1338.190 250tidyr_replace_na 680.4478 973.1395 978.2678 1003.9797 1051.2624 1294.376 250baseR.for 670.7897 965.6312 983.5775 1001.5229 1052.5946 1206.023 250DT.for.set.nms 496.8031 569.7471 695.4339 623.1086 861.1918 1067.640 250DT.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))
当数据集变大时,Tidyr的 replace_na 历史上已经退出了前面 . 目前收集50M要运行的数据点,它几乎与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
mutate
summarize
_at
_all
特别感谢:
Tyler Rinker和Akrun用于演示微基准 .
alexis_laz致力于帮助我理解 local() 的使用,以及(在弗兰克的耐心帮助下)静音强制在加速许多这些方法中所起的作用 .
local()
ArthurYip用于戳添加更新的 coalesce() 函数并更新分析 .
coalesce()
格雷戈尔为了轻松搞清楚 data.table 功能,最终将他们列入阵容 .
Base R For循环:alexis_laz
data.table For循环:Matt_Dowle
(当然,如果你发现这些方法有用的话,也请到达并给予他们投票 . )
Note on my use of Numerics: 如果您有纯整数数据集,则所有函数都将运行得更快 . 有关更多信息,请参阅alexiz_laz's work . IRL,我不记得遇到包含超过10-15%整数的数据集,所以我在完全数字数据帧上运行这些测试 .
dplyr示例:
library(dplyr) df1 <- df1 %>% mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))
Note: 这适用于每个选定的列,如果我们需要对所有列执行此操作,请参阅使用mutate_each的@reidjax的答案 .
我知道这个问题已经回答了,但这样做对某些人来说可能更有用:
定义此功能:
na.zero <- function (x) { x[is.na(x)] <- 0 return(x) }
现在,无论何时需要将向量中的NA转换为零,您都可以:
na.zero(some.vector)
14 回答
如果我们在导出时尝试替换
NA
,例如在写入csv时,我们可以使用:使用
dplyr
0.5.0,您可以使用coalesce
函数,通过执行coalesce(vec, 0)
可以轻松地将其集成到%>%
管道中 . 这将取代vec
中的所有NAs为0:假设我们有一个
NA
的数据框:在@ gsk3回答中查看我的评论 . 一个简单的例子:
没有必要申请
apply
. =)EDIT
您还应该看一下
norm
包 . 它有很多很好的功能,可用于缺少数据分析 . =)在矩阵或向量中使用
replace()
替换NA
到0
的更一般方法例如:
这也是在
dplyr
中使用ifelse()
的替代方法你可以使用
replace()
例如:
从Datacamp中提取的这个简单函数可以帮助:
然后
另一个使用 imputeTS 包的例子:
另一个
dplyr
管道兼容选项,tidyr
方法replace_na
适用于多个列:您可以轻松限制为例如数字列:
've commented on @ianmunoz'的帖子,但我没有足够的声誉 . 你可以组合
dplyr
的mutate_each
和replace
来处理NA
到0
的替换 . 使用来自@ aL3xa答案的数据框...我们在这里使用标准评估(SE),这就是为什么我们需要“
funs_
”的下划线 . 我们还使用lazyeval
的interp
/~
和.
引用"everything we are working with",即数据帧 . 现在有零!对于单个向量:
对于data.frame,从上面创建一个函数,然后
apply
到列 .请在下次详细说明下提供可重现的示例:
How to make a great R reproducible example?
如果要在因子变量中替换NA,这可能很有用:
它将因子矢量转换为数字矢量,并添加另一个人工数字因子级别,然后将其转换回因子矢量,并选择一个额外的“NA级别” .
混合dplyr / Base R选项:
mutate_all(funs(replace(., is.na(.), 0))))
的速度是基本Rd[is.na(d)] <- 0
选项的两倍多 . (请参阅下面的基准分析 . )如果您正在努力应对海量数据帧,
data.table
是最快的选择:比dplyr少30%的时间,比Base R接近3倍 . 它还可以修改数据,有效地允许您同时处理几乎两倍的数据 .其他有用的tidyverse替换方法的聚类
Locationally:
index
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()
,试试ends_with()
,starts_with()
模式匹配
mutate_at(vars(matches("\\d{2}")), funs(replace(., is.na(.), 0)))
Conditionally:
(仅更改数字(列)并单独保留字符串(列) . )
整数
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)))
完整分析 -
测试方法:
此分析的代码:
结果摘要
结果箱图(以对数刻度)
颜色编码的试验散点图(以对数刻度)
关于其他高绩效者的说明
当数据集变大时,Tidyr的
replace_na
历史上已经退出了前面 . 目前收集50M要运行的数据点,它几乎与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归因和赞赏
特别感谢:
Tyler Rinker和Akrun用于演示微基准 .
alexis_laz致力于帮助我理解
local()
的使用,以及(在弗兰克的耐心帮助下)静音强制在加速许多这些方法中所起的作用 .ArthurYip用于戳添加更新的
coalesce()
函数并更新分析 .格雷戈尔为了轻松搞清楚
data.table
功能,最终将他们列入阵容 .Base R For循环:alexis_laz
data.table For循环:Matt_Dowle
(当然,如果你发现这些方法有用的话,也请到达并给予他们投票 . )
Note on my use of Numerics: 如果您有纯整数数据集,则所有函数都将运行得更快 . 有关更多信息,请参阅alexiz_laz's work . IRL,我不记得遇到包含超过10-15%整数的数据集,所以我在完全数字数据帧上运行这些测试 .
dplyr示例:
Note: 这适用于每个选定的列,如果我们需要对所有列执行此操作,请参阅使用mutate_each的@reidjax的答案 .
我知道这个问题已经回答了,但这样做对某些人来说可能更有用:
定义此功能:
现在,无论何时需要将向量中的NA转换为零,您都可以: