在R中,如何用前一个字符替换NA



有一个数据帧为blow(具有NA值(

md <- data.frame(cat=c('a','b','d',NA,'E',NA),
subcat=c('A','C',NA,NA,NA,'D')) 
cat subcat
1    a      A
2    b      C
3    d   <NA>
4 <NA>   <NA>
5    E   <NA>
6 <NA>      D

我想用前面的字符替换NA,结果如下。

正在使用类似"for…"的循环语句可以做到,但效率不高。有什么配方或包装可以做到这一点吗?谢谢

cat subcat
1   a      A
2   b      C
3   d      C
4   d      C
5   E      C
6   E      D

您可以使用zoo包中的na.locf函数。

zoo::na.locf(md)
cat subcat
1   a      A
2   b      C
3   d      C
4   d      C
5   E      C
6   E      D

或者分别使用tidyrdplyr中的filleverything

library(dplyr)
library(tidyr)
md %>% fill(everything())
#   cat subcat
# 1   a      A
# 2   b      C
# 3   d      C
# 4   d      C
# 5   E      C
# 6   E      D

一种方法是使用行程长度编码rle()。因为它不编码NA,所以我用字符串"替换了它们;NA";。

roll_na <- function(.) {
.[is.na(.)] <- "NA"
var <- rle(.)
na_ind <- which(var$values == "NA")
var_lag <- c(NA, var$values[-length(var$values)])
var$values[na_ind] <- var_lag[na_ind]

rep(var$values, times = var$lengths)
}
library(dplyr)
md %>% 
mutate(across(everything(), roll_na))
#   cat subcat
# 1   a      A
# 2   b      C
# 3   d      C
# 4   d      C
# 5   E      C
# 6   E      D

如果在大列向量中有很多连续的NA,这不是一种方法,但如果只有几个,它会很快:

no_NA <- function(x) {while(any(is.na(x))) x[is.na(x)] <- x[which(is.na(x))-1]; x}
as.data.frame(apply(md, 2, no_NA))

如果你有一个有很多NAs的大数据集,我会使用一个简单的while循环,它会从每个向量的开始改变所有的NAs

no_NA <- function(x){
len <- length(x); i <- 2
while(i <= len){
if (is.na(x[i])) x[i] <- x[i-1]
i <- i + 1
} 
x
}
as.data.frame(apply(md, 2, no_NA))

忽略NA是列的初始值的情况,可以使用以下函数

# Replacement function
func = function(DF){
tmp = DF
for(i in 1:length(tmp[1,])){
for(j in 1:length(tmp[,i])){
if(j == 1){
next
} else if (is.na(tmp[j,i])) {
tmp[j,i] = tmp[j-1,i]
}
}
}
return(tmp)
}

# data 
md = func(md)
print(md)

输出

cat subcat
1   a      A
2   b      C
3   d      C
4   d      C
5   E      C
6   E      D
library(tidyverse)
library(magrittr)
#> 
#> Attaching package: 'magrittr'
#> The following object is masked from 'package:purrr':
#> 
#>     set_names
#> The following object is masked from 'package:tidyr':
#> 
#>     extract
md <- data.frame(cat=c(NA,'b','d',NA,'E',NA),
subcat=c(NA,'C',NA,NA,NA,'D')) 
md
#>    cat subcat
#> 1 <NA>   <NA>
#> 2    b      C
#> 3    d   <NA>
#> 4 <NA>   <NA>
#> 5    E   <NA>
#> 6 <NA>      D
#if the first value is NA
value <- '0'
md <- 
map(md, ~{
if(is.na(.x[[1]])) {
c(value, .x[-1])
} else {
.x
}
}) %>% bind_cols()
#while loop is needed for consecutive NA's
while (any(map_lgl(md, ~any(is.na(..1))))) { 
md %<>% mutate(cat = if_else(is.na(cat), lag(cat), cat),
subcat = if_else(is.na(subcat), lag(subcat), subcat))
}
md
#> # A tibble: 6 x 2
#>   cat   subcat
#>   <chr> <chr> 
#> 1 0     0     
#> 2 b     C     
#> 3 d     C     
#> 4 d     C     
#> 5 E     C     
#> 6 E     D

创建于2021-06-11由reprex包(v2.0.0(

最新更新