我想用 NA 值所在的列中的非 NA 值的平均值填充数据框中的 NA 值。例如,在下面的数据框ab中,我想将b列中的所有NA替换为(5 + 6 + 7(/3 = 6,因为这是b列中所有非NA值的平均值。我想对所有其他列做同样的事情。
ab<-data.frame(a=c(1,2,3,4),b=c(NA,5,6,7),c=c(4,NA,5,6),d=c(3,NA,NA,5))
a b c d
1 1 NA 4 3
2 2 5 NA NA
3 3 6 5 NA
4 4 7 6 5
我写了下面来做到这一点。
lapply(ab,function(b){lapply(b,function(c){c=ifelse (is.na(c)==TRUE,mean(b,na.rm=TRUE),c)})})
结果是
$a
$a[[1]]
[1] 1
$a[[2]]
[1] 2
$a[[3]]
[1] 3
$a[[4]]
[1] 4
$b
$b[[1]]
[1] 6
$b[[2]]
[1] 5
$b[[3]]
[1] 6
$b[[4]]
[1] 7
$c
$c[[1]]
[1] 4
$c[[2]]
[1] 5
$c[[3]]
[1] 5
$c[[4]]
[1] 6
$d
$d[[1]]
[1] 3
$d[[2]]
[1] 4
$d[[3]]
[1] 4
$d[[4]]
[1] 5
而不是
a b c d
1 1 6 4 3
2 2 5 5 4
3 3 6 5 4
4 4 7 6 5
如果我这样做
as.data.frame(lapply(ab,function(b){lapply(b,function(c){c=ifelse (is.na(c)==TRUE,mean(b,na.rm=TRUE),c)})}))
希望将lapply的结果转换为数据框,我得到
a.1 a.2 a.3 a.4 b.6 b.5 b.6.1 b.7 c.4 c.5 c.5.1 c.6 d.3 d.4 d.4.1 d.5
1 1 2 3 4 6 5 6 7 4 5 5 6 3 4 4 5
这是什么意思? 如何获得所需的结果?我确实看到 R 输出是表示所需结果的另一种方式,但我想要输出数据框的预期常规外观。
您还可以使用purrr
包中的map_if
函数:
library(dplyr)
library(purrr)
ab %>%
map_if(~ any(is.na(.x)), ~ replace(.x, is.na(.x), mean(.x, na.rm = TRUE))) %>%
bind_cols()
# A tibble: 4 x 4
a b c d
<dbl> <dbl> <dbl> <dbl>
1 1 6 4 3
2 2 5 5 4
3 3 6 5 4
4 4 7 6 5
我们也可以用coalesce
替换replace
:
ab %>%
map_if(~ any(is.na(.x)), ~ coalesce(.x, mean(.x, na.rm = TRUE))) %>%
bind_cols()
使用zoo
中的na.aggregate
library(zoo)
library(dplyr)
ab %>%
mutate(across(everything(), na.aggregate))
-输出
a b c d
1 1 6 4 3
2 2 5 5 4
3 3 6 5 4
4 4 7 6 5
此外,默认情况下,na.aggregate
将 NA 逐列替换为这些相应列的mean
。 因此,它可以更紧凑,因为
na.aggregate(ab)
a b c d
1 1 6 4 3
2 2 5 5 4
3 3 6 5 4
4 4 7 6 5
k<-sapply(ab,function(b){lapply(b,function(c){c=ifelse(is.na(c)==TRUE,mean(b,na.rm=TRUE),c)})})
ans<-as.data.frame(k,nrow=4,ncol=4)
给
a b c d
1 1 6 4 3
2 2 5 5 4
3 3 6 5 4
4 4 7 6 5
您可以使用lapply
-
ab[] <- lapply(ab, function(x) replace(x, is.na(x), mean(x, na.rm = TRUE)))
# a b c d
#1 1 6 4 3
#2 2 5 5 4
#3 3 6 5 4
#4 4 7 6 5
或者用dplyr
——
library(dplyr)
ab %>% mutate(across(.fns = ~replace(., is.na(.), mean(., na.rm = TRUE))))