r语言 - 使用 lapply 填充数据框中的 NA 值



我想用 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))))

最新更新